Browse Source

Merge remote-tracking branch 'Stan/development' into development

kindlich 6 years ago
parent
commit
1ae12a4538
No known key found for this signature in database
100 changed files with 3180 additions and 1442 deletions
  1. 3
    2
      CompilerShared/src/main/java/org/openzen/zenscript/compiler/SemanticModule.java
  2. 3
    3
      Constructor/src/main/java/org/openzen/zenscript/constructor/Library.java
  3. 10
    5
      Constructor/src/main/java/org/openzen/zenscript/constructor/Main.java
  4. 10
    6
      Constructor/src/main/java/org/openzen/zenscript/constructor/Module.java
  5. 6
    2
      Constructor/src/main/java/org/openzen/zenscript/constructor/ModuleLoader.java
  6. 7
    5
      Constructor/src/main/java/org/openzen/zenscript/constructor/Project.java
  7. 7
    7
      Constructor/src/main/java/org/openzen/zenscript/constructor/module/DirectoryModuleReference.java
  8. 4
    1
      Constructor/src/main/java/org/openzen/zenscript/constructor/module/ModuleReference.java
  9. 87
    37
      DrawableGui/src/main/java/org/openzen/drawablegui/DButton.java
  10. 0
    67
      DrawableGui/src/main/java/org/openzen/drawablegui/DCanvas.java
  11. 3
    1
      DrawableGui/src/main/java/org/openzen/drawablegui/DColorableIcon.java
  12. 104
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/DColorableIconInstance.java
  13. 5
    8
      DrawableGui/src/main/java/org/openzen/drawablegui/DComponent.java
  14. 6
    4
      DrawableGui/src/main/java/org/openzen/drawablegui/DCompositeIcon.java
  15. 3
    1
      DrawableGui/src/main/java/org/openzen/drawablegui/DDrawable.java
  16. 94
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/DDrawableInstance.java
  17. 7
    6
      DrawableGui/src/main/java/org/openzen/drawablegui/DEmptyView.java
  18. 4
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/DFontMetrics.java
  19. 0
    273
      DrawableGui/src/main/java/org/openzen/drawablegui/DHorizontalLayout.java
  20. 0
    31
      DrawableGui/src/main/java/org/openzen/drawablegui/DHorizontalLayoutStyle.java
  21. 40
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/DIRectangle.java
  22. 98
    49
      DrawableGui/src/main/java/org/openzen/drawablegui/DInputField.java
  23. 6
    19
      DrawableGui/src/main/java/org/openzen/drawablegui/DInputFieldStyle.java
  24. 38
    12
      DrawableGui/src/main/java/org/openzen/drawablegui/DLabel.java
  25. 49
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/DPath.java
  26. 24
    48
      DrawableGui/src/main/java/org/openzen/drawablegui/DSimpleTooltip.java
  27. 128
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/DSimpleTooltipComponent.java
  28. 3
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/DSimpleTooltipStyle.java
  29. 0
    26
      DrawableGui/src/main/java/org/openzen/drawablegui/DTooltip.java
  30. 0
    2
      DrawableGui/src/main/java/org/openzen/drawablegui/DUIContext.java
  31. 1
    1
      DrawableGui/src/main/java/org/openzen/drawablegui/DUIWindow.java
  32. 0
    274
      DrawableGui/src/main/java/org/openzen/drawablegui/DVerticalLayout.java
  33. 0
    31
      DrawableGui/src/main/java/org/openzen/drawablegui/DVerticalLayoutStyle.java
  34. 22
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/Destructible.java
  35. 15
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DBorder.java
  36. 9
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DCompositeBorder.java
  37. 63
    42
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DCustomWindowBorder.java
  38. 9
    2
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DEmptyBorder.java
  39. 15
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DLineBorder.java
  40. 11
    2
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DPaddedBorder.java
  41. 107
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/border/DSideBorder.java
  42. 22
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawSurface.java
  43. 37
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawTarget.java
  44. 14
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnColorableElement.java
  45. 20
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnElement.java
  46. 16
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnRectangle.java
  47. 3
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnShape.java
  48. 21
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnText.java
  49. 24
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/draw/DSubSurface.java
  50. 42
    25
      DrawableGui/src/main/java/org/openzen/drawablegui/form/DForm.java
  51. 463
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/layout/DLinearLayout.java
  52. 24
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/layout/DLinearLayoutStyle.java
  53. 40
    20
      DrawableGui/src/main/java/org/openzen/drawablegui/layout/DSideLayout.java
  54. 20
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/layout/DSideLayoutStyle.java
  55. 30
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/live/InverseLiveBool.java
  56. 2
    2
      DrawableGui/src/main/java/org/openzen/drawablegui/live/LiveConcatList.java
  57. 5
    2
      DrawableGui/src/main/java/org/openzen/drawablegui/live/LiveMappedList.java
  58. 2
    2
      DrawableGui/src/main/java/org/openzen/drawablegui/live/LivePredicateBool.java
  59. 8
    1
      DrawableGui/src/main/java/org/openzen/drawablegui/live/SimpleLiveInt.java
  60. 3
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/live/SimpleLiveObject.java
  61. 3
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/live/SimpleLiveString.java
  62. 49
    24
      DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollBar.java
  63. 56
    127
      DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollPane.java
  64. 3
    6
      DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollPaneStyle.java
  65. 45
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DBaseStyle.java
  66. 22
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DBorderElement.java
  67. 23
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DColorElement.java
  68. 6
    1
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DDimension.java
  69. 16
    7
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DEmptyStyleDefinition.java
  70. 23
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DEmptyStylesheet.java
  71. 1
    1
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DEmptyStylesheets.java
  72. 23
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DFontElement.java
  73. 49
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DMargin.java
  74. 20
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DMarginElement.java
  75. 2
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DPxDimension.java
  76. 23
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DRectangleShape.java
  77. 36
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DRoundedRectangleShape.java
  78. 1
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DShadow.java
  79. 21
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DShadowElement.java
  80. 17
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DShape.java
  81. 22
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DShapeElement.java
  82. 100
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DSimpleStylesheet.java
  83. 13
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStyleClass.java
  84. 7
    5
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStyleDefinition.java
  85. 45
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStyleElement.java
  86. 4
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylePath.java
  87. 12
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylePathRoot.java
  88. 16
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylesheet.java
  89. 66
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylesheetBuilder.java
  90. 0
    209
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingCanvas.java
  91. 22
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDialog.java
  92. 202
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawSurface.java
  93. 35
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawnElement.java
  94. 57
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawnRectangle.java
  95. 68
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawnText.java
  96. 75
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingFilledPath.java
  97. 29
    19
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingGraphicsContext.java
  98. 156
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingInlineWindow.java
  99. 15
    3
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingRoot.java
  100. 0
    0
      DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingShadowedPath.java

+ 3
- 2
CompilerShared/src/main/java/org/openzen/zenscript/compiler/SemanticModule.java View File

@@ -9,6 +9,7 @@ import java.util.ArrayList;
9 9
 import java.util.HashMap;
10 10
 import java.util.List;
11 11
 import java.util.Map;
12
+import java.util.function.Consumer;
12 13
 import org.openzen.zenscript.codemodel.annotations.AnnotationDefinition;
13 14
 import org.openzen.zenscript.codemodel.HighLevelDefinition;
14 15
 import org.openzen.zenscript.codemodel.PackageDefinitions;
@@ -93,7 +94,7 @@ public class SemanticModule {
93 94
 				annotations);
94 95
 	}
95 96
 	
96
-	public boolean validate() {
97
+	public boolean validate(Consumer<ValidationLogEntry> logger) {
97 98
 		if (state != State.NORMALIZED)
98 99
 			throw new IllegalStateException("Module is not yet normalized");
99 100
 		
@@ -106,7 +107,7 @@ public class SemanticModule {
106 107
 		}
107 108
 		
108 109
 		for (ValidationLogEntry entry : validator.getLog()) {
109
-			System.out.println(entry.kind + " " + entry.position.toString() + ": " + entry.message);
110
+			logger.accept(entry);
110 111
 		}
111 112
 		state = validator.hasErrors() ? State.INVALID : State.VALIDATED;
112 113
 		return !validator.hasErrors();

+ 3
- 3
Constructor/src/main/java/org/openzen/zenscript/constructor/Library.java View File

@@ -8,7 +8,7 @@ package org.openzen.zenscript.constructor;
8 8
 import java.io.File;
9 9
 import org.json.JSONArray;
10 10
 import org.json.JSONObject;
11
-import org.openzen.zenscript.constructor.module.DirectoryModuleLoader;
11
+import org.openzen.zenscript.constructor.module.DirectoryModuleReference;
12 12
 import org.openzen.zenscript.constructor.module.ModuleReference;
13 13
 
14 14
 /**
@@ -20,7 +20,7 @@ public class Library {
20 20
 	public final File directory;
21 21
 	public final ModuleReference[] modules;
22 22
 	
23
-	public Library(ModuleLoader loader, File directory, String name, JSONObject json) {
23
+	public Library(File directory, String name, JSONObject json) {
24 24
 		this.name = name;
25 25
 		this.directory = new File(directory, json.getString("directory"));
26 26
 		
@@ -28,7 +28,7 @@ public class Library {
28 28
 		modules = new ModuleReference[modulesJson.length()];
29 29
 		for (int i = 0; i < modulesJson.length(); i++) {
30 30
 			String moduleName = modulesJson.getString(i);
31
-			modules[i] = new DirectoryModuleLoader(loader, moduleName, new File(this.directory, moduleName), false);
31
+			modules[i] = new DirectoryModuleReference(moduleName, new File(this.directory, moduleName), false);
32 32
 		}
33 33
 	}
34 34
 }

+ 10
- 5
Constructor/src/main/java/org/openzen/zenscript/constructor/Main.java View File

@@ -1,9 +1,11 @@
1 1
 package org.openzen.zenscript.constructor;
2 2
 
3
-import org.openzen.zenscript.compiler.CompilationUnit;
4 3
 import java.io.File;
4
+import org.openzen.zenscript.compiler.CompilationUnit;
5 5
 import java.io.IOException;
6
-import org.openzen.zenscript.constructor.module.DirectoryModuleLoader;
6
+import java.util.function.Consumer;
7
+import org.openzen.zencode.shared.CompileException;
8
+import org.openzen.zenscript.constructor.module.DirectoryModuleReference;
7 9
 import org.openzen.zenscript.constructor.module.ModuleReference;
8 10
 
9 11
 public class Main {
@@ -18,12 +20,15 @@ public class Main {
18 20
 			return;
19 21
 		}
20 22
 		
23
+		Consumer<CompileException> exceptionLogger = exception -> System.err.println(exception.toString());
24
+		
21 25
 		File currentDirectory = new File(arguments.directory);
22 26
 		CompilationUnit compilationUnit = new CompilationUnit();
23
-		ModuleLoader moduleLoader = new ModuleLoader(compilationUnit);
24
-		moduleLoader.register("stdlib", new DirectoryModuleLoader(moduleLoader, "stdlib", new File("../../StdLibs/stdlib"), true));
25 27
 		
26
-		Project project = new Project(moduleLoader, currentDirectory);
28
+		ModuleLoader moduleLoader = new ModuleLoader(compilationUnit, exceptionLogger);
29
+		moduleLoader.register("stdlib", new DirectoryModuleReference("stdlib", new File("../../StdLibs/stdlib"), true));
30
+		
31
+		Project project = new Project(currentDirectory);
27 32
 		for (Library library : project.libraries) {
28 33
 			for (ModuleReference module : library.modules)
29 34
 				moduleLoader.register(module.getName(), module);

+ 10
- 6
Constructor/src/main/java/org/openzen/zenscript/constructor/Module.java View File

@@ -13,6 +13,7 @@ import java.util.ArrayList;
13 13
 import java.util.Collections;
14 14
 import java.util.List;
15 15
 import java.util.Map;
16
+import java.util.function.Consumer;
16 17
 import org.json.JSONArray;
17 18
 import org.json.JSONObject;
18 19
 import org.json.JSONTokener;
@@ -36,10 +37,12 @@ public class Module {
36 37
 	public final File sourceDirectory;
37 38
 	public final String packageName;
38 39
 	public final String host;
40
+	private final Consumer<CompileException> exceptionLogger;
39 41
 	
40
-	public Module(String name, File directory, File moduleFile) throws IOException {
42
+	public Module(String name, File directory, File moduleFile, Consumer<CompileException> exceptionLogger) throws IOException {
41 43
 		this.name = name;
42 44
 		this.sourceDirectory = new File(directory, "src");
45
+		this.exceptionLogger = exceptionLogger;
43 46
 		
44 47
 		BufferedInputStream input = new BufferedInputStream(new FileInputStream(moduleFile));
45 48
 		JSONObject json = new JSONObject(new JSONTokener(input));
@@ -67,7 +70,7 @@ public class Module {
67 70
 				try {
68 71
 					files.add(ParsedFile.parse(pkg, file));
69 72
 				} catch (CompileException ex) {
70
-					System.out.println(ex.getMessage());
73
+					exceptionLogger.accept(ex);
71 74
 				}
72 75
 			} else if (file.isDirectory()) {
73 76
 				parse(files, pkg.getOrCreatePackage(file.getName()), file);
@@ -80,7 +83,8 @@ public class Module {
80 83
 			String[] dependencies,
81 84
 			ZSPackage pkg,
82 85
 			ParsedFile[] files,
83
-			ModuleSpace registry) {
86
+			ModuleSpace registry,
87
+			Consumer<CompileException> exceptionLogger) {
84 88
 		// We are considering all these files to be in the same package, so make
85 89
 		// a single PackageDefinition instance. If these files were in multiple
86 90
 		// packages, we'd need an instance for every package.
@@ -106,7 +110,7 @@ public class Module {
106 110
 			try {
107 111
 				file.compileTypes(rootPackage, pkg, definitions, registry.compilationUnit.globalTypeRegistry, expansions, globals, registry.getAnnotations());
108 112
 			} catch (CompileException ex) {
109
-				System.out.println(ex.getMessage());
113
+				exceptionLogger.accept(ex);
110 114
 				failed = true;
111 115
 			}
112 116
 		}
@@ -121,7 +125,7 @@ public class Module {
121 125
 			try {
122 126
 				file.compileMembers(rootPackage, pkg, definitions, registry.compilationUnit.globalTypeRegistry, expansions, globals, registry.getAnnotations());
123 127
 			} catch (CompileException ex) {
124
-				System.out.println(ex.getMessage());
128
+				exceptionLogger.accept(ex);
125 129
 				failed = true;
126 130
 			}
127 131
 		}
@@ -138,7 +142,7 @@ public class Module {
138 142
 			try {
139 143
 				file.compileCode(rootPackage, pkg, definitions, registry.compilationUnit.globalTypeRegistry, expansions, scripts, globals, registry.getAnnotations());
140 144
 			} catch (CompileException ex) {
141
-				System.out.println(ex.getMessage());
145
+				exceptionLogger.accept(ex);
142 146
 				failed = true;
143 147
 			}
144 148
 		}

+ 6
- 2
Constructor/src/main/java/org/openzen/zenscript/constructor/ModuleLoader.java View File

@@ -10,6 +10,8 @@ import java.util.HashMap;
10 10
 import java.util.HashSet;
11 11
 import java.util.Map;
12 12
 import java.util.Stack;
13
+import java.util.function.Consumer;
14
+import org.openzen.zencode.shared.CompileException;
13 15
 import org.openzen.zenscript.constructor.module.ModuleReference;
14 16
 import org.openzen.zenscript.compiler.SemanticModule;
15 17
 
@@ -25,9 +27,11 @@ public class ModuleLoader {
25 27
 	private final Stack<String> compilingModulesStack = new Stack<>();
26 28
 	
27 29
 	private final CompilationUnit compilationUnit;
30
+	private final Consumer<CompileException> exceptionLogger;
28 31
 	
29
-	public ModuleLoader(CompilationUnit compilationUnit) {
32
+	public ModuleLoader(CompilationUnit compilationUnit, Consumer<CompileException> exceptionLogger) {
30 33
 		this.compilationUnit = compilationUnit;
34
+		this.exceptionLogger = exceptionLogger;
31 35
 	}
32 36
 	
33 37
 	public SemanticModule getModule(String name) {
@@ -49,7 +53,7 @@ public class ModuleLoader {
49 53
 		compilingModulesSet.add(name);
50 54
 		compilingModulesStack.add(name);
51 55
 		
52
-		SemanticModule module = modules.get(name).load(compilationUnit);
56
+		SemanticModule module = modules.get(name).load(this, compilationUnit, exceptionLogger);
53 57
 		moduleCache.put(name, module);
54 58
 		
55 59
 		compilingModulesSet.remove(name);

+ 7
- 5
Constructor/src/main/java/org/openzen/zenscript/constructor/Project.java View File

@@ -9,9 +9,11 @@ import java.io.File;
9 9
 import java.io.IOException;
10 10
 import java.util.ArrayList;
11 11
 import java.util.List;
12
+import java.util.function.Consumer;
12 13
 import org.json.JSONArray;
13 14
 import org.json.JSONObject;
14
-import org.openzen.zenscript.constructor.module.DirectoryModuleLoader;
15
+import org.openzen.zencode.shared.CompileException;
16
+import org.openzen.zenscript.constructor.module.DirectoryModuleReference;
15 17
 import org.openzen.zenscript.constructor.module.ModuleReference;
16 18
 import org.openzen.zenscript.compiler.Target;
17 19
 import org.openzen.zenscript.compiler.TargetType;
@@ -27,7 +29,7 @@ public class Project {
27 29
 	public final Library[] libraries;
28 30
 	public final Target[] targets;
29 31
 	
30
-	public Project(ModuleLoader loader, File directory) throws IOException {
32
+	public Project(File directory) throws IOException {
31 33
 		this.directory = directory;
32 34
 		name = directory.getName();
33 35
 		
@@ -46,7 +48,7 @@ public class Project {
46 48
 		libraries = new Library[jsonLibraries.length()];
47 49
 		int k = 0;
48 50
 		for (String key : jsonLibraries.keySet()) {
49
-			libraries[k] = new Library(loader, directory, key, jsonLibraries.getJSONObject(key));
51
+			libraries[k] = new Library(directory, key, jsonLibraries.getJSONObject(key));
50 52
 			k++;
51 53
 		}
52 54
 		
@@ -55,13 +57,13 @@ public class Project {
55 57
 		for (int i = 0; i < jsonModules.length(); i++) {
56 58
 			Object module = jsonModules.get(i);
57 59
 			if (module instanceof String) {
58
-				modules[i] = new DirectoryModuleLoader(loader, module.toString(), new File(directory, module.toString()), false);
60
+				modules[i] = new DirectoryModuleReference(module.toString(), new File(directory, module.toString()), false);
59 61
 			} else if (module instanceof JSONObject) {
60 62
 				JSONObject jsonModule = (JSONObject) module;
61 63
 				String name = jsonModule.getString("name");
62 64
 				switch (jsonModule.getString("type")) {
63 65
 					case "directory":
64
-						modules[i] = new DirectoryModuleLoader(loader, name, new File(directory, jsonModule.getString("directory")), false);
66
+						modules[i] = new DirectoryModuleReference(name, new File(directory, jsonModule.getString("directory")), false);
65 67
 						break;
66 68
 					default:
67 69
 						throw new ConstructorException("Invalid module type: " + jsonModule.getString("type"));

Constructor/src/main/java/org/openzen/zenscript/constructor/module/DirectoryModuleLoader.java → Constructor/src/main/java/org/openzen/zenscript/constructor/module/DirectoryModuleReference.java View File

@@ -10,8 +10,10 @@ import java.io.File;
10 10
 import java.io.IOException;
11 11
 import java.util.ArrayList;
12 12
 import java.util.List;
13
+import java.util.function.Consumer;
13 14
 import org.json.JSONArray;
14 15
 import org.json.JSONObject;
16
+import org.openzen.zencode.shared.CompileException;
15 17
 import org.openzen.zenscript.codemodel.definition.ZSPackage;
16 18
 import org.openzen.zenscript.compiler.CompilationUnit;
17 19
 import org.openzen.zenscript.constructor.ConstructorException;
@@ -25,15 +27,13 @@ import org.openzen.zenscript.parser.ParsedFile;
25 27
  *
26 28
  * @author Hoofdgebruiker
27 29
  */
28
-public class DirectoryModuleLoader implements ModuleReference {
29
-	private final ModuleLoader loader;
30
+public class DirectoryModuleReference implements ModuleReference {
30 31
 	private final String moduleName;
31 32
 	private final File directory;
32 33
 	private final boolean isStdlib;
33 34
 	private SourcePackage rootPackage = null;
34 35
 	
35
-	public DirectoryModuleLoader(ModuleLoader loader, String moduleName, File directory, boolean isStdlib) {
36
-		this.loader = loader;
36
+	public DirectoryModuleReference(String moduleName, File directory, boolean isStdlib) {
37 37
 		this.moduleName = moduleName;
38 38
 		this.directory = directory;
39 39
 		this.isStdlib = isStdlib;
@@ -45,7 +45,7 @@ public class DirectoryModuleLoader implements ModuleReference {
45 45
 	}
46 46
 
47 47
 	@Override
48
-	public SemanticModule load(CompilationUnit unit) {
48
+	public SemanticModule load(ModuleLoader loader, CompilationUnit unit, Consumer<CompileException> exceptionLogger) {
49 49
 		if (!directory.exists())
50 50
 			throw new ConstructorException("Error: module directory not found: " + directory);
51 51
 		
@@ -71,11 +71,11 @@ public class DirectoryModuleLoader implements ModuleReference {
71 71
 			for (String dependencyName : dependencyNames)
72 72
 				space.addModule(dependencyName, loader.getModule(dependencyName));
73 73
 
74
-			Module module = new Module(moduleName, directory, jsonFile);
74
+			Module module = new Module(moduleName, directory, jsonFile, exceptionLogger);
75 75
 			ZSPackage pkg = isStdlib ? unit.globalTypeRegistry.stdlib : new ZSPackage(null, module.packageName);
76 76
 
77 77
 			ParsedFile[] parsedFiles = module.parse(pkg);
78
-			SemanticModule result = Module.compileSyntaxToSemantic(module.name, module.dependencies, pkg, parsedFiles, space);
78
+			SemanticModule result = Module.compileSyntaxToSemantic(module.name, module.dependencies, pkg, parsedFiles, space, exceptionLogger);
79 79
 			
80 80
 			JSONObject globals = json.optJSONObject("globals");
81 81
 			if (globals != null) {

+ 4
- 1
Constructor/src/main/java/org/openzen/zenscript/constructor/module/ModuleReference.java View File

@@ -5,8 +5,11 @@
5 5
  */
6 6
 package org.openzen.zenscript.constructor.module;
7 7
 
8
+import java.util.function.Consumer;
9
+import org.openzen.zencode.shared.CompileException;
8 10
 import org.openzen.zenscript.compiler.SemanticModule;
9 11
 import org.openzen.zenscript.compiler.CompilationUnit;
12
+import org.openzen.zenscript.constructor.ModuleLoader;
10 13
 
11 14
 /**
12 15
  *
@@ -15,7 +18,7 @@ import org.openzen.zenscript.compiler.CompilationUnit;
15 18
 public interface ModuleReference {
16 19
 	public String getName();
17 20
 	
18
-	public SemanticModule load(CompilationUnit unit);
21
+	public SemanticModule load(ModuleLoader loader, CompilationUnit unit, Consumer<CompileException> exceptionLogger);
19 22
 	
20 23
 	public SourcePackage getRootPackage();
21 24
 }

+ 87
- 37
DrawableGui/src/main/java/org/openzen/drawablegui/DButton.java View File

@@ -5,6 +5,9 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawSurface;
9
+import org.openzen.drawablegui.draw.DDrawnShape;
10
+import org.openzen.drawablegui.draw.DDrawnText;
8 11
 import org.openzen.drawablegui.live.LiveBool;
9 12
 import org.openzen.drawablegui.live.LiveObject;
10 13
 import org.openzen.drawablegui.live.LiveString;
@@ -24,7 +27,8 @@ public class DButton implements DComponent {
24 27
 	private final LiveBool disabled;
25 28
 	private final Runnable action;
26 29
 	
27
-	private DUIContext context;
30
+	private DDrawSurface surface;
31
+	private int z;
28 32
 	private DIRectangle bounds;
29 33
 	
30 34
 	private DButtonStyle style;
@@ -33,24 +37,40 @@ public class DButton implements DComponent {
33 37
 	private boolean hovering = false;
34 38
 	private boolean pressing = false;
35 39
 	
40
+	private DDrawnShape shape;
41
+	private DDrawnText text;
42
+	private DShadow currentShadow;
43
+	
36 44
 	public DButton(DStyleClass styleClass, LiveString label, LiveBool disabled, Runnable action) {
37 45
 		this.styleClass = styleClass;
38 46
 		this.label = label;
39 47
 		this.disabled = disabled;
40 48
 		this.action = action;
41 49
 	}
42
-
50
+	
43 51
 	@Override
44
-	public void setContext(DStylePath parent, DUIContext context) {
45
-		this.context = context;
52
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
53
+		this.surface = surface;
54
+		this.z = z;
46 55
 		
47 56
 		DStylePath path = parent.getChild("Button", styleClass);
48
-		this.style = new DButtonStyle(context.getStylesheets().get(context, path));
49
-		fontMetrics = context.getFontMetrics(style.font);
57
+		this.style = new DButtonStyle(surface.getStylesheet(path));
58
+		fontMetrics = surface.getFontMetrics(style.font);
50 59
 		
51 60
 		sizing.setValue(new DSizing(
52 61
 				style.paddingLeft + style.paddingRight + fontMetrics.getWidth(label.getValue()),
53 62
 				style.paddingTop + style.paddingBottom + fontMetrics.getAscent() + fontMetrics.getDescent()));
63
+		currentShadow = getShadow();
64
+	}
65
+	
66
+	@Override
67
+	public void unmount() {
68
+		surface = null;
69
+		
70
+		if (shape != null)
71
+			shape.close();
72
+		if (text != null)
73
+			text.close();
54 74
 	}
55 75
 
56 76
 	@Override
@@ -71,53 +91,49 @@ public class DButton implements DComponent {
71 91
 	@Override
72 92
 	public void setBounds(DIRectangle bounds) {
73 93
 		this.bounds = bounds;
74
-	}
75
-
76
-	@Override
77
-	public void paint(DCanvas canvas) {
78
-		int backgroundColor = style.backgroundColorNormal;
79
-		DShadow shadow = style.shadowNormal;
80
-		if (hovering) {
81
-			backgroundColor = style.backgroundColorHover;
82
-			shadow = style.shadowNormal;
83
-		}
84
-		if (pressing) {
85
-			backgroundColor = style.backgroundColorPress;
86
-			shadow = style.shadowPress;
87
-		}
88
-		if (disabled.getValue()) {
89
-			backgroundColor = style.backgroundColorDisabled;
90
-			shadow = style.shadowDisabled;
91
-		}
92 94
 		
93
-		DPath shape = DPath.roundedRectangle(bounds.x, bounds.y, bounds.width, bounds.height, 2 * context.getScale());
94
-		canvas.shadowPath(shape, DTransform2D.IDENTITY, shadow);
95
-		canvas.fillPath(shape, DTransform2D.IDENTITY, backgroundColor);
96
-		canvas.drawText(style.font, style.textColor, bounds.x + style.paddingLeft, bounds.y + style.paddingTop + fontMetrics.getAscent(), label.getValue());
95
+		if (shape != null)
96
+			shape.close();
97
+		if (text != null)
98
+			text.close();
99
+		
100
+		shape = surface.shadowPath(
101
+				z,
102
+				DPath.roundedRectangle(bounds.x, bounds.y, bounds.width, bounds.height, 2 * surface.getScale()),
103
+				DTransform2D.IDENTITY,
104
+				getBackgroundColor(),
105
+				currentShadow);
106
+		text = surface.drawText(
107
+				z +  1, 
108
+				style.font,
109
+				style.textColor,
110
+				bounds.x + style.paddingLeft,
111
+				bounds.y + style.paddingTop + fontMetrics.getAscent(),
112
+				label.getValue());
97 113
 	}
98 114
 
99 115
 	@Override
100 116
 	public void close() {
101
-		
117
+		unmount();
102 118
 	}
103 119
 	
104 120
 	@Override
105 121
 	public void onMouseEnter(DMouseEvent e) {
106 122
 		hovering = true;
107
-		repaint();
123
+		update();
108 124
 	}
109 125
 	
110 126
 	@Override
111 127
 	public void onMouseExit(DMouseEvent e) {
112 128
 		hovering = false;
113 129
 		pressing = false;
114
-		repaint();
130
+		update();
115 131
 	}
116 132
 	
117 133
 	@Override
118 134
 	public void onMouseDown(DMouseEvent e) {
119 135
 		pressing = true;
120
-		repaint();
136
+		update();
121 137
 	}
122 138
 	
123 139
 	@Override
@@ -128,13 +144,47 @@ public class DButton implements DComponent {
128 144
 			action.run();
129 145
 		}
130 146
 		
131
-		repaint();
147
+		update();
148
+	}
149
+	
150
+	private void update() {
151
+		DShadow newShadow = getShadow();
152
+		if (newShadow != currentShadow) {
153
+			currentShadow = newShadow;
154
+			
155
+			if (shape != null)
156
+				shape.close();
157
+			
158
+			shape = surface.shadowPath(
159
+				z,
160
+				DPath.roundedRectangle(bounds.x, bounds.y, bounds.width, bounds.height, 2 * surface.getScale()),
161
+				DTransform2D.IDENTITY,
162
+				getBackgroundColor(),
163
+				currentShadow);
164
+		} else {
165
+			shape.setColor(getBackgroundColor());
166
+		}
167
+	}
168
+	
169
+	private DShadow getShadow() {
170
+		if (disabled.getValue())
171
+			return style.shadowDisabled;
172
+		if (pressing)
173
+			return style.shadowPress;
174
+		if (hovering)
175
+			return style.shadowHover;
176
+		
177
+		return style.shadowNormal;
132 178
 	}
133 179
 	
134
-	private void repaint() {
135
-		if (context == null || bounds == null)
136
-			return;
180
+	private int getBackgroundColor() {
181
+		if (disabled.getValue())
182
+			return style.backgroundColorDisabled;
183
+		if (pressing)
184
+			return style.backgroundColorPress;
185
+		if (hovering)
186
+			return style.backgroundColorHover;
137 187
 		
138
-		context.repaint(bounds);
188
+		return style.backgroundColorNormal;
139 189
 	}
140 190
 }

+ 0
- 67
DrawableGui/src/main/java/org/openzen/drawablegui/DCanvas.java View File

@@ -1,67 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui;
7
-
8
-import org.openzen.drawablegui.style.DShadow;
9
-
10
-/**
11
- *
12
- * @author Hoofdgebruiker
13
- */
14
-public interface DCanvas {
15
-	void pushBounds(DIRectangle bounds);
16
-	
17
-	void popBounds();
18
-	
19
-	void pushOffset(int x, int y);
20
-	
21
-	void popOffset();
22
-	
23
-	DIRectangle getBounds();
24
-	
25
-	DUIContext getContext();
26
-	
27
-	void drawText(DFont font, int color, float x, float y, String text);
28
-	
29
-	/**
30
-	 * Strokes a given path.
31
-	 * 
32
-	 * @param path path to be stroked
33
-	 * @param transform path transform
34
-	 * @param color path color
35
-	 * @param lineWidth path line width
36
-	 */
37
-	void strokePath(DPath path, DTransform2D transform, int color, float lineWidth);
38
-	
39
-	/**
40
-	 * Fills a given path.
41
-	 * 
42
-	 * @param path path to be filled
43
-	 * @param transform 
44
-	 * @param color
45
-	 */
46
-	void fillPath(DPath path, DTransform2D transform, int color);
47
-	
48
-	/**
49
-	 * Draws the shadow for a given path.
50
-	 * 
51
-	 * @param path
52
-	 * @param transform
53
-	 * @param shadow
54
-	 */
55
-	void shadowPath(DPath path, DTransform2D transform, DShadow shadow);
56
-	
57
-	/**
58
-	 * Fills a rectangle.
59
-	 * 
60
-	 * @param x
61
-	 * @param y
62
-	 * @param width
63
-	 * @param height
64
-	 * @param color 
65
-	 */
66
-	void fillRectangle(int x, int y, int width, int height, int color);
67
-}

+ 3
- 1
DrawableGui/src/main/java/org/openzen/drawablegui/DColorableIcon.java View File

@@ -5,12 +5,14 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawTarget;
9
+
8 10
 /**
9 11
  *
10 12
  * @author Hoofdgebruiker
11 13
  */
12 14
 public interface DColorableIcon {
13
-	void draw(DCanvas canvas, DTransform2D transform, int color);
15
+	void draw(DDrawTarget target, int z, DTransform2D transform, int color);
14 16
 	
15 17
 	float getNominalWidth();
16 18
 	

+ 104
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DColorableIconInstance.java View File

@@ -0,0 +1,104 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui;
7
+
8
+import java.io.Closeable;
9
+import java.util.ArrayList;
10
+import java.util.List;
11
+import org.openzen.drawablegui.draw.DDrawSurface;
12
+import org.openzen.drawablegui.draw.DDrawTarget;
13
+import org.openzen.drawablegui.draw.DDrawnColorableElement;
14
+import org.openzen.drawablegui.draw.DDrawnElement;
15
+import org.openzen.drawablegui.draw.DDrawnRectangle;
16
+import org.openzen.drawablegui.draw.DDrawnShape;
17
+import org.openzen.drawablegui.draw.DDrawnText;
18
+import org.openzen.drawablegui.style.DShadow;
19
+
20
+/**
21
+ *
22
+ * @author Hoofdgebruiker
23
+ */
24
+public final class DColorableIconInstance implements Closeable {
25
+	private final List<DDrawnElement> elements = new ArrayList<>();
26
+	private final List<DDrawnColorableElement> colorables = new ArrayList<>();
27
+	
28
+	public DColorableIconInstance(DDrawSurface surface, int z, DColorableIcon icon, DTransform2D transform, int color) {
29
+		icon.draw(new DrawTarget(surface), z, transform, DDrawTarget.INSTANCE_COLOR);
30
+		setColor(color);
31
+	}
32
+	
33
+	public void setColor(int color) {
34
+		for (DDrawnColorableElement colorable : colorables)
35
+			colorable.setColor(color);
36
+	}
37
+	
38
+	public void setTransform(DTransform2D transform) {
39
+		for (DDrawnElement element : elements)
40
+			element.setTransform(transform);
41
+	}
42
+	
43
+	@Override
44
+	public void close() {
45
+		for (DDrawnElement element : elements)
46
+			element.close();
47
+	}
48
+	
49
+	private class DrawTarget implements DDrawTarget {
50
+		private final DDrawSurface surface;
51
+		
52
+		public DrawTarget(DDrawSurface surface) {
53
+			this.surface = surface;
54
+		}
55
+
56
+		@Override
57
+		public DFontMetrics getFontMetrics(DFont font) {
58
+			return surface.getFontMetrics(font);
59
+		}
60
+
61
+		@Override
62
+		public float getScale() {
63
+			return surface.getScale();
64
+		}
65
+
66
+		@Override
67
+		public float getTextScale() {
68
+			return surface.getTextScale();
69
+		}
70
+
71
+		@Override
72
+		public DDrawnText drawText(int z, DFont font, int color, float x, float y, String text) {
73
+			return addColorable(surface.drawText(z, font, color, x, y, text), color);
74
+		}
75
+
76
+		@Override
77
+		public DDrawnRectangle fillRect(int z, DIRectangle rectangle, int color) {
78
+			return addColorable(surface.fillRect(z, rectangle, color), color);
79
+		}
80
+
81
+		@Override
82
+		public DDrawnShape strokePath(int z, DPath path, DTransform2D transform, int color, float lineWidth) {
83
+			return addColorable(surface.strokePath(z, path, transform, color, lineWidth), color);
84
+		}
85
+
86
+		@Override
87
+		public DDrawnShape fillPath(int z, DPath path, DTransform2D transform, int color) {
88
+			return addColorable(surface.fillPath(z, path, transform, color), color);
89
+		}
90
+
91
+		@Override
92
+		public DDrawnShape shadowPath(int z, DPath path, DTransform2D transform, int color, DShadow shadow) {
93
+			return addColorable(surface.shadowPath(z, path, transform, color, shadow), color);
94
+		}
95
+		
96
+		private <T extends DDrawnColorableElement> T addColorable(T colorable, int color) {
97
+			if (color == DDrawTarget.INSTANCE_COLOR)
98
+				colorables.add(colorable);
99
+			
100
+			elements.add(colorable);
101
+			return colorable;
102
+		}
103
+	}
104
+}

+ 5
- 8
DrawableGui/src/main/java/org/openzen/drawablegui/DComponent.java View File

@@ -5,7 +5,7 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
-import java.io.Closeable;
8
+import org.openzen.drawablegui.draw.DDrawSurface;
9 9
 import org.openzen.drawablegui.live.LiveObject;
10 10
 import org.openzen.drawablegui.style.DStylePath;
11 11
 
@@ -13,8 +13,10 @@ import org.openzen.drawablegui.style.DStylePath;
13 13
  *
14 14
  * @author Hoofdgebruiker
15 15
  */
16
-public interface DComponent extends Closeable {
17
-	void setContext(DStylePath parent, DUIContext context);
16
+public interface DComponent extends Destructible {
17
+	void mount(DStylePath parent, int z, DDrawSurface surface);
18
+	
19
+	void unmount();
18 20
 	
19 21
 	LiveObject<DSizing> getSizing();
20 22
 	
@@ -24,8 +26,6 @@ public interface DComponent extends Closeable {
24 26
 	
25 27
 	void setBounds(DIRectangle bounds);
26 28
 	
27
-	void paint(DCanvas canvas);
28
-	
29 29
 	default void onMounted() {}
30 30
 	
31 31
 	default void onUnmounted() {}
@@ -55,7 +55,4 @@ public interface DComponent extends Closeable {
55 55
 	default void onKeyPressed(DKeyEvent e) {}
56 56
 	
57 57
 	default void onKeyReleased(DKeyEvent e) {}
58
-	
59
-	@Override
60
-	void close();
61 58
 }

+ 6
- 4
DrawableGui/src/main/java/org/openzen/drawablegui/DCompositeIcon.java View File

@@ -5,6 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawTarget;
9
+
8 10
 /**
9 11
  *
10 12
  * @author Hoofdgebruiker
@@ -19,11 +21,11 @@ public class DCompositeIcon implements DColorableIcon {
19 21
 		this.addition = addition;
20 22
 		this.additionTransform = additionTransform;
21 23
 	}
22
-
24
+	
23 25
 	@Override
24
-	public void draw(DCanvas canvas, DTransform2D transform, int color) {
25
-		base.draw(canvas, transform, color);
26
-		addition.draw(canvas, transform.mul(additionTransform), color);
26
+	public void draw(DDrawTarget target, int z, DTransform2D transform, int color) {
27
+		base.draw(target, z, transform, color);
28
+		addition.draw(target, z + 1, transform.mul(additionTransform), color);
27 29
 	}
28 30
 
29 31
 	@Override

+ 3
- 1
DrawableGui/src/main/java/org/openzen/drawablegui/DDrawable.java View File

@@ -5,12 +5,14 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawTarget;
9
+
8 10
 /**
9 11
  *
10 12
  * @author Hoofdgebruiker
11 13
  */
12 14
 public interface DDrawable {
13
-	void draw(DCanvas canvas, DTransform2D transform);
15
+	void draw(DDrawTarget target, int z, DTransform2D transform);
14 16
 	
15 17
 	float getNominalWidth();
16 18
 	

+ 94
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DDrawableInstance.java View File

@@ -0,0 +1,94 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui;
7
+
8
+import java.io.Closeable;
9
+import java.util.ArrayList;
10
+import java.util.List;
11
+import org.openzen.drawablegui.draw.DDrawSurface;
12
+import org.openzen.drawablegui.draw.DDrawTarget;
13
+import org.openzen.drawablegui.draw.DDrawnColorableElement;
14
+import org.openzen.drawablegui.draw.DDrawnElement;
15
+import org.openzen.drawablegui.draw.DDrawnRectangle;
16
+import org.openzen.drawablegui.draw.DDrawnShape;
17
+import org.openzen.drawablegui.draw.DDrawnText;
18
+import org.openzen.drawablegui.style.DShadow;
19
+
20
+/**
21
+ *
22
+ * @author Hoofdgebruiker
23
+ */
24
+public class DDrawableInstance implements Closeable {
25
+	private final List<DDrawnElement> elements = new ArrayList<>();
26
+	
27
+	public DDrawableInstance(DDrawSurface surface, int z, DDrawable icon, DTransform2D transform) {
28
+		icon.draw(new DrawTarget(surface), z, transform);
29
+	}
30
+	
31
+	public void setTransform(DTransform2D transform) {
32
+		for (DDrawnElement element : elements)
33
+			element.setTransform(transform);
34
+	}
35
+	
36
+	@Override
37
+	public void close() {
38
+		for (DDrawnElement element : elements)
39
+			element.close();
40
+	}
41
+	
42
+	private class DrawTarget implements DDrawTarget {
43
+		private final DDrawSurface surface;
44
+		
45
+		public DrawTarget(DDrawSurface surface) {
46
+			this.surface = surface;
47
+		}
48
+
49
+		@Override
50
+		public DFontMetrics getFontMetrics(DFont font) {
51
+			return surface.getFontMetrics(font);
52
+		}
53
+
54
+		@Override
55
+		public float getScale() {
56
+			return surface.getScale();
57
+		}
58
+
59
+		@Override
60
+		public float getTextScale() {
61
+			return surface.getTextScale();
62
+		}
63
+
64
+		@Override
65
+		public DDrawnText drawText(int z, DFont font, int color, float x, float y, String text) {
66
+			return addElement(surface.drawText(z, font, color, x, y, text));
67
+		}
68
+
69
+		@Override
70
+		public DDrawnRectangle fillRect(int z, DIRectangle rectangle, int color) {
71
+			return addElement(surface.fillRect(z, rectangle, color));
72
+		}
73
+
74
+		@Override
75
+		public DDrawnShape strokePath(int z, DPath path, DTransform2D transform, int color, float lineWidth) {
76
+			return addElement(surface.strokePath(z, path, transform, color, lineWidth));
77
+		}
78
+
79
+		@Override
80
+		public DDrawnShape fillPath(int z, DPath path, DTransform2D transform, int color) {
81
+			return addElement(surface.fillPath(z, path, transform, color));
82
+		}
83
+
84
+		@Override
85
+		public DDrawnShape shadowPath(int z, DPath path, DTransform2D transform, int color, DShadow shadow) {
86
+			return addElement(surface.shadowPath(z, path, transform, color, shadow));
87
+		}
88
+		
89
+		private <T extends DDrawnColorableElement> T addElement(T colorable) {
90
+			elements.add(colorable);
91
+			return colorable;
92
+		}
93
+	}
94
+}

+ 7
- 6
DrawableGui/src/main/java/org/openzen/drawablegui/DEmptyView.java View File

@@ -5,6 +5,7 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawSurface;
8 9
 import org.openzen.drawablegui.live.ImmutableLiveObject;
9 10
 import org.openzen.drawablegui.live.LiveObject;
10 11
 import org.openzen.drawablegui.style.DStylePath;
@@ -21,7 +22,12 @@ public class DEmptyView implements DComponent {
21 22
 	private DEmptyView() {}
22 23
 
23 24
 	@Override
24
-	public void setContext(DStylePath parent, DUIContext context) {
25
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
26
+		
27
+	}
28
+	
29
+	@Override
30
+	public void unmount() {
25 31
 		
26 32
 	}
27 33
 	
@@ -45,11 +51,6 @@ public class DEmptyView implements DComponent {
45 51
 		
46 52
 	}
47 53
 
48
-	@Override
49
-	public void paint(DCanvas canvas) {
50
-		
51
-	}
52
-
53 54
 	@Override
54 55
 	public void close() {
55 56
 		// nothing to clean up

+ 4
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DFontMetrics.java View File

@@ -19,4 +19,8 @@ public interface DFontMetrics {
19 19
 	int getWidth(String str);
20 20
 	
21 21
 	int getWidth(String str, int offset, int length);
22
+	
23
+	default int getLineHeight() {
24
+		return getAscent() + getDescent();
25
+	}
22 26
 }

+ 0
- 273
DrawableGui/src/main/java/org/openzen/drawablegui/DHorizontalLayout.java View File

@@ -1,273 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui;
7
-
8
-import java.util.function.Consumer;
9
-import java.util.function.Predicate;
10
-import org.openzen.drawablegui.listeners.ListenerHandle;
11
-import org.openzen.drawablegui.live.LiveObject;
12
-import org.openzen.drawablegui.live.MutableLiveObject;
13
-import org.openzen.drawablegui.live.SimpleLiveObject;
14
-import org.openzen.drawablegui.style.DStyleClass;
15
-import org.openzen.drawablegui.style.DStylePath;
16
-
17
-/**
18
- *
19
- * @author Hoofdgebruiker
20
- */
21
-public class DHorizontalLayout extends BaseComponentGroup {
22
-	private final DStyleClass styleClass;
23
-	private final Alignment alignment;
24
-	private final Element[] components;
25
-	private final ListenerHandle<LiveObject.Listener<DSizing>>[] componentSizeListeners;
26
-	private final MutableLiveObject<DSizing> sizing = DSizing.create();
27
-	
28
-	private DUIContext context;
29
-	private DHorizontalLayoutStyle style;
30
-	private DIRectangle bounds;
31
-	private float totalGrow;
32
-	private float totalShrink;
33
-	
34
-	public DHorizontalLayout(DStyleClass styleClass, Alignment alignment, Element... components) {
35
-		this.styleClass = styleClass;
36
-		this.alignment = alignment;
37
-		this.components = components;
38
-		
39
-		componentSizeListeners = new ListenerHandle[components.length];
40
-		totalGrow = 0;
41
-		totalShrink = 0;
42
-		
43
-		for (int i = 0; i < componentSizeListeners.length; i++) {
44
-			componentSizeListeners[i] = components[i].component.getSizing().addListener((oldValue, newValue) -> updateDimensionPreferences());
45
-			
46
-			totalGrow += components[i].grow;
47
-			totalShrink += components[i].shrink;
48
-		}
49
-	}
50
-
51
-	@Override
52
-	protected void forEachChild(Consumer<DComponent> children) {
53
-		for (Element element : components)
54
-			children.accept(element.component);
55
-	}
56
-
57
-	@Override
58
-	protected DComponent findChild(Predicate<DComponent> predicate) {
59
-		for (Element element : components)
60
-			if (predicate.test(element.component))
61
-				return element.component;
62
-		
63
-		return null;
64
-	}
65
-
66
-	@Override
67
-	public void setContext(DStylePath parent, DUIContext context) {
68
-		this.context = context;
69
-		
70
-		DStylePath path = parent.getChild("horizontalLayout", styleClass);
71
-		style = new DHorizontalLayoutStyle(context.getStylesheets().get(context, path));
72
-		
73
-		for (Element element : components)
74
-			element.component.setContext(parent, context);
75
-		
76
-		layout();
77
-	}
78
-
79
-	@Override
80
-	public LiveObject<DSizing> getSizing() {
81
-		return sizing;
82
-	}
83
-
84
-	@Override
85
-	public DIRectangle getBounds() {
86
-		return bounds;
87
-	}
88
-
89
-	@Override
90
-	public int getBaselineY() {
91
-		return components[0].component.getBaselineY();
92
-	}
93
-
94
-	@Override
95
-	public void setBounds(DIRectangle bounds) {
96
-		this.bounds = bounds;
97
-		layout();
98
-	}
99
-
100
-	@Override
101
-	public void paint(DCanvas canvas) {
102
-		for (Element element : components) {
103
-			element.component.paint(canvas);
104
-		}
105
-	}
106
-
107
-	@Override
108
-	public void close() {
109
-		for (int i = 0; i < componentSizeListeners.length; i++) {
110
-			componentSizeListeners[i].close();
111
-		}
112
-	}
113
-	
114
-	public static enum Alignment {
115
-		LEFT(0),
116
-		CENTER(0.5f),
117
-		RIGHT(1);
118
-		
119
-		public final float align;
120
-		
121
-		Alignment(float align) {
122
-			this.align = align;
123
-		}
124
-	}
125
-	
126
-	public static enum ElementAlignment {
127
-		TOP,
128
-		MIDDLE,
129
-		BOTTOM,
130
-		STRETCH
131
-	}
132
-	
133
-	public static class Element {
134
-		public final DComponent component;
135
-		public final float grow;
136
-		public final float shrink;
137
-		public final ElementAlignment alignment;
138
-		
139
-		public Element(DComponent component, float grow, float shrink, ElementAlignment alignment) {
140
-			this.component = component;
141
-			this.grow = grow;
142
-			this.shrink = shrink;
143
-			this.alignment = alignment;
144
-		}
145
-	}
146
-	
147
-	private void layout() {
148
-		if (bounds == null || context == null)
149
-			return;
150
-		
151
-		DSizing myPreferences = sizing.getValue();
152
-		if (bounds.width < myPreferences.preferredWidth) {
153
-			layoutShrinked();
154
-		} else {
155
-			layoutGrown();
156
-		}
157
-	}
158
-	
159
-	private void layoutShrinked() {
160
-		DSizing myPreferences = sizing.getValue();
161
-		if (totalShrink == 0) {
162
-			// now what?
163
-			// shrink proportionally, we have to shrink...
164
-			float scale = (float)(bounds.width - (components.length - 1) * style.spacing) / (myPreferences.preferredWidth - (components.length - 1) * style.spacing);
165
-			int x = 0;
166
-			
167
-			for (int i = 0; i < components.length; i++) {
168
-				Element element = components[i];
169
-				DSizing preferences = element.component.getSizing().getValue();
170
-				int newX = x + preferences.preferredWidth;
171
-				float idealUnspacedX = newX * scale;
172
-				int idealX = (int)(idealUnspacedX + 0.5f + i * style.spacing);
173
-				layout(element, x, idealX - x);
174
-				x = idealX;
175
-			}
176
-		} else {
177
-			int delta = bounds.width - myPreferences.preferredWidth;
178
-			float deltaScaled = delta / totalShrink;
179
-			int x = 0;
180
-			for (Element element : components) {
181
-				DSizing preferences = element.component.getSizing().getValue();
182
-				float scaledSize = preferences.preferredWidth + deltaScaled * element.shrink;
183
-				float idealUnspacedX = x + scaledSize;
184
-				int newX = (int)(idealUnspacedX + 0.5f);
185
-				layout(element, x, newX - x);
186
-				x = newX + style.spacing;
187
-			}
188
-		}
189
-	}
190
-	
191
-	private void layoutGrown() {
192
-		// resize according to grow values
193
-		DSizing myPreferences = sizing.getValue();
194
-		
195
-		if (totalGrow == 0) {
196
-			int deltaX = (int)(myPreferences.preferredWidth - bounds.width);
197
-			int x = bounds.x + (int)(deltaX * alignment.align);
198
-			for (Element element : components) {
199
-				DSizing preferences = element.component.getSizing().getValue();
200
-				int newX = x + preferences.preferredWidth;
201
-				layout(element, x, newX - x);
202
-				x = newX + style.spacing;
203
-			}
204
-		} else {
205
-			int delta = bounds.width - myPreferences.preferredWidth;
206
-			float deltaScaled = delta / totalGrow;
207
-			int x = 0;
208
-			for (Element element : components) {
209
-				DSizing preferences = element.component.getSizing().getValue();
210
-				float scaledSize = preferences.preferredWidth + deltaScaled * element.grow;
211
-				float idealUnspacedX = x + scaledSize;
212
-				int newX = (int)(idealUnspacedX + 0.5f);
213
-				layout(element, x, newX - x);
214
-				x = newX + style.spacing;
215
-			}
216
-		}
217
-	}
218
-	
219
-	private void layout(Element element, int x, int width) {
220
-		DSizing preferences = element.component.getSizing().getValue();
221
-		int height;
222
-		int y;
223
-		switch (element.alignment) {
224
-			case BOTTOM:
225
-				height = Math.min(preferences.preferredHeight, bounds.height - style.paddingTop - style.paddingBottom);
226
-				y = bounds.y + style.paddingTop;
227
-				break;
228
-			case MIDDLE:
229
-				height = Math.min(preferences.preferredHeight, bounds.height - style.paddingTop - style.paddingBottom);
230
-				y = bounds.y + style.paddingTop + (bounds.height - style.paddingTop - style.paddingBottom - height) / 2;
231
-				break;
232
-			case TOP:
233
-				height = Math.min(preferences.preferredHeight, bounds.height - style.paddingTop - style.paddingBottom);
234
-				y = bounds.y + bounds.height - style.paddingBottom - height;
235
-				break;
236
-			case STRETCH:
237
-			default:
238
-				height = bounds.height - style.paddingTop - style.paddingBottom;
239
-				y = bounds.y + style.paddingTop;
240
-				break;
241
-		}
242
-		element.component.setBounds(new DIRectangle(x, y, width, height));
243
-	}
244
-	
245
-	private void updateDimensionPreferences() {
246
-		int preferredWidth = -style.spacing;
247
-		int preferredHeight = 0;
248
-		int minimumWidth = -style.spacing;
249
-		int minimumHeight = 0;
250
-		int maximumWidth = -style.spacing;
251
-		int maximumHeight = Integer.MAX_VALUE;
252
-		for (Element element : components) {
253
-			DSizing preferences = element.component.getSizing().getValue();
254
-			preferredWidth += preferences.preferredWidth + style.spacing;
255
-			preferredHeight = Math.max(preferredHeight, preferences.preferredHeight);
256
-			
257
-			minimumWidth += preferences.minimumWidth + style.spacing;
258
-			minimumHeight = Math.max(minimumHeight, preferences.minimumHeight);
259
-			
260
-			maximumWidth += preferences.maximumWidth + style.spacing;
261
-			maximumHeight = Math.min(maximumHeight, preferences.maximumHeight);
262
-		}
263
-		
264
-		DSizing preferences = new DSizing(
265
-				minimumWidth + style.paddingLeft + style.paddingRight,
266
-				minimumHeight + style.paddingTop + style.paddingBottom,
267
-				preferredWidth + style.paddingLeft + style.paddingRight,
268
-				preferredHeight + style.paddingTop + style.paddingBottom,
269
-				maximumWidth + style.paddingLeft + style.paddingRight,
270
-				maximumHeight + style.paddingTop + style.paddingBottom);
271
-		sizing.setValue(preferences);
272
-	}
273
-}

+ 0
- 31
DrawableGui/src/main/java/org/openzen/drawablegui/DHorizontalLayoutStyle.java View File

@@ -1,31 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui;
7
-
8
-import org.openzen.drawablegui.style.DDpDimension;
9
-import org.openzen.drawablegui.style.DStyleDefinition;
10
-
11
-/**
12
- *
13
- * @author Hoofdgebruiker
14
- */
15
-public class DHorizontalLayoutStyle {
16
-	public final int spacing;
17
-	
18
-	public final int paddingTop;
19
-	public final int paddingLeft;
20
-	public final int paddingRight;
21
-	public final int paddingBottom;
22
-	
23
-	public DHorizontalLayoutStyle(DStyleDefinition style) {
24
-		spacing = style.getDimension("spacing", new DDpDimension(8));
25
-		
26
-		paddingTop = style.getDimension("paddingTop", new DDpDimension(8));
27
-		paddingLeft = style.getDimension("paddingLeft", new DDpDimension(8));
28
-		paddingRight = style.getDimension("paddingRight", new DDpDimension(8));
29
-		paddingBottom = style.getDimension("paddingBottom", new DDpDimension(8));
30
-	}
31
-}

+ 40
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DIRectangle.java View File

@@ -42,6 +42,46 @@ public class DIRectangle {
42 42
 				&& y >= this.y && y < (this.y + this.height);
43 43
 	}
44 44
 	
45
+	public boolean overlaps(DIRectangle other) {
46
+		if (x + width < other.x)
47
+			return false;
48
+		if (y + height < other.y)
49
+			return false;
50
+		if (other.x + other.width < x)
51
+			return false;
52
+		if (other.y + other.height < y)
53
+			return false;
54
+		
55
+		return true;
56
+	}
57
+	
58
+	public DIRectangle offset(int x, int y) {
59
+		return new DIRectangle(this.x + x, this.y + y, width, height);
60
+	}
61
+	
62
+	public DIRectangle expand(int edge) {
63
+		return new DIRectangle(x - edge, y - edge, width + 2 * edge, height + 2 * edge);
64
+	}
65
+	
66
+	public DIRectangle union(DIRectangle other) {
67
+		int left = Math.min(x, other.x);
68
+		int top = Math.min(y, other.y);
69
+		int right = Math.max(x + width, other.x + other.width);
70
+		int bottom = Math.max(y + height, other.y + other.height);
71
+		return new DIRectangle(left, top, right - left, bottom - top);
72
+	}
73
+	
74
+	public DIRectangle intersect(DIRectangle other) {
75
+		int left = Math.max(x, other.x);
76
+		int top = Math.max(y, other.y);
77
+		int right = Math.min(x + width, other.x + other.width);
78
+		int bottom = Math.min(y + height, other.y + other.height);
79
+		if (right < left || bottom < top)
80
+			return EMPTY;
81
+		
82
+		return new DIRectangle(left, top, right - left, bottom - top);
83
+	}
84
+	
45 85
 	@Override
46 86
 	public String toString() {
47 87
 		return "(x = " + x + ", y = " + y + ", width = " + width + ", height = " + height + ")";

+ 98
- 49
DrawableGui/src/main/java/org/openzen/drawablegui/DInputField.java View File

@@ -5,6 +5,10 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawSurface;
9
+import org.openzen.drawablegui.draw.DDrawnRectangle;
10
+import org.openzen.drawablegui.draw.DDrawnShape;
11
+import org.openzen.drawablegui.draw.DDrawnText;
8 12
 import org.openzen.drawablegui.listeners.ListenerHandle;
9 13
 import org.openzen.drawablegui.live.LiveObject;
10 14
 import org.openzen.drawablegui.live.LiveString;
@@ -27,7 +31,8 @@ public class DInputField implements DComponent {
27 31
 	private DIRectangle bounds = DIRectangle.EMPTY;
28 32
 	private final DDimension preferredWidth;
29 33
 	
30
-	private DUIContext context;
34
+	private DDrawSurface surface;
35
+	private int z;
31 36
 	private DInputFieldStyle style;
32 37
 	private DFontMetrics fontMetrics;
33 38
 	private int cursorFrom = -1;
@@ -39,6 +44,11 @@ public class DInputField implements DComponent {
39 44
 	private boolean cursorBlink = true;
40 45
 	private DTimerHandle blinkTimer;
41 46
 	
47
+	private DDrawnShape shape;
48
+	private DDrawnText text;
49
+	private DDrawnRectangle cursor;
50
+	private DDrawnRectangle selection;
51
+	
42 52
 	public DInputField(DStyleClass styleClass, MutableLiveString value, DDimension preferredWidth) {
43 53
 		this.styleClass = styleClass;
44 54
 		this.value = value;
@@ -60,28 +70,66 @@ public class DInputField implements DComponent {
60 70
 	@Override
61 71
 	public void close() {
62 72
 		valueListener.close();
63
-		blinkTimer.close();
73
+		unmount();
64 74
 	}
65 75
 
66 76
 	@Override
67
-	public void setContext(DStylePath parent, DUIContext context) {
68
-		this.context = context;
77
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
78
+		this.surface = surface;
79
+		this.z = z;
69 80
 		
70 81
 		DStylePath path = parent.getChild("input", styleClass);
71
-		style = new DInputFieldStyle(context.getStylesheets().get(context, path));
72
-		fontMetrics = context.getFontMetrics(style.font);
82
+		style = new DInputFieldStyle(surface.getStylesheet(path));
83
+		fontMetrics = surface.getFontMetrics(style.font);
84
+		
73 85
 		sizing.setValue(new DSizing(
74
-				preferredWidth.evalInt(context) + style.paddingLeft + style.paddingRight + 2 * style.borderWidth,
75
-				fontMetrics.getAscent() + fontMetrics.getDescent() + style.paddingTop + style.paddingBottom + 2 * style.borderWidth));
86
+				preferredWidth.evalInt(surface.getContext()) + style.margin.getHorizontal() + style.border.getPaddingHorizontal(),
87
+				fontMetrics.getAscent() + fontMetrics.getDescent() + style.margin.getVertical() + style.border.getPaddingVertical()));
76 88
 		
77 89
 		if (blinkTimer != null)
78 90
 			blinkTimer.close();
79
-		blinkTimer = context.setTimer(300, this::blink);
91
+		blinkTimer = surface.getContext().setTimer(300, this::blink);
92
+		
93
+		if (text != null)
94
+			text.close();
95
+		text = surface.drawText(
96
+				z + 2,
97
+				style.font,
98
+				style.color,
99
+				bounds.x + style.margin.left + style.border.getPaddingLeft(),
100
+				bounds.y + style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent(),
101
+				value.getValue());
102
+		
103
+		if (cursor != null)
104
+			cursor.close();
105
+		cursor = surface.fillRect(z + 2, DIRectangle.EMPTY, cursorBlink ? style.cursorColor : 0);
106
+		
107
+		if (selection != null)
108
+			selection.close();
109
+		selection = surface.fillRect(z + 1, DIRectangle.EMPTY, 0);
110
+		
111
+		setCursor(cursorFrom, cursorTo);
112
+	}
113
+	
114
+	@Override
115
+	public void unmount() {
116
+		blinkTimer.close();
117
+		
118
+		if (style != null)
119
+			style.border.close();
120
+		if (shape != null)
121
+			shape.close();
122
+		if (text != null)
123
+			text.close();
124
+		if (cursor != null)
125
+			cursor.close();
126
+		if (selection != null)
127
+			selection.close();
80 128
 	}
81 129
 	
82 130
 	private void blink() {
83 131
 		cursorBlink = !cursorBlink;
84
-		context.repaint(bounds);
132
+		cursor.setColor(cursorBlink ? style.cursorColor : 0);
85 133
 	}
86 134
 
87 135
 	@Override
@@ -96,61 +144,36 @@ public class DInputField implements DComponent {
96 144
 	
97 145
 	@Override
98 146
 	public int getBaselineY() {
99
-		return style.borderWidth + style.paddingTop + fontMetrics.getAscent();
147
+		return style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent();
100 148
 	}
101 149
 
102 150
 	@Override
103 151
 	public void setBounds(DIRectangle bounds) {
104 152
 		this.bounds = bounds;
105
-	}
106
-
107
-	@Override
108
-	public void paint(DCanvas canvas) {
109
-		canvas.fillRectangle(bounds.x, bounds.y, bounds.width, bounds.height, style.backgroundColor);
110
-		if (style.borderWidth > 0) {
111
-			canvas.strokePath(
112
-					DPath.rectangle(bounds.x, bounds.y, bounds.width - style.borderWidth, bounds.height - style.borderWidth),
113
-					DTransform2D.IDENTITY,
114
-					style.borderColor,
115
-					style.borderWidth);
116
-		}
153
+		setCursor(cursorFrom, cursorTo);
117 154
 		
118
-		int cursorXFrom = fontMetrics.getWidth(value.getValue(), 0, Math.min(cursorFrom, cursorTo));
119
-		int cursorXTo = fontMetrics.getWidth(value.getValue(), 0, Math.max(cursorFrom, cursorTo));
120
-		if (cursorFrom != cursorTo) {
121
-			canvas.fillRectangle(
122
-					bounds.x + style.paddingLeft + cursorXFrom,
123
-					bounds.y + style.paddingTop,
124
-					cursorXTo - cursorXFrom,
125
-					fontMetrics.getAscent() + fontMetrics.getDescent(),
126
-					style.selectionColor);
127
-		}
128
-		
129
-		canvas.drawText(style.font, style.color, bounds.x + style.paddingLeft + style.borderWidth, bounds.y + style.paddingBottom + style.borderWidth + fontMetrics.getAscent(), value.getValue());
130
-		
131
-		if (cursorBlink) {
132
-			canvas.fillRectangle(
133
-					bounds.x + style.paddingLeft + cursorXTo,
134
-					bounds.y + style.paddingTop,
135
-					style.cursorWidth,
136
-					fontMetrics.getAscent() + fontMetrics.getDescent(),
137
-					style.cursorColor);
138
-		}
155
+		if (shape != null)
156
+			shape.close();
157
+		shape = surface.fillPath(z, style.shape.instance(style.margin.apply(bounds)), DTransform2D.IDENTITY, style.backgroundColor);
158
+		text.setPosition(
159
+				bounds.x + style.margin.left + style.border.getPaddingLeft(),
160
+				bounds.y + style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent());
161
+		style.border.update(surface, z, bounds);
139 162
 	}
140 163
 	
141 164
 	@Override
142 165
 	public void onMouseEnter(DMouseEvent e) {
143
-		context.setCursor(DUIContext.Cursor.TEXT);
166
+		surface.getContext().setCursor(DUIContext.Cursor.TEXT);
144 167
 	}
145 168
 	
146 169
 	@Override
147 170
 	public void onMouseExit(DMouseEvent e) {
148
-		context.setCursor(DUIContext.Cursor.NORMAL);
171
+		surface.getContext().setCursor(DUIContext.Cursor.NORMAL);
149 172
 	}
150 173
 	
151 174
 	@Override
152 175
 	public void onMouseClick(DMouseEvent e) {
153
-		context.getWindow().focus(this);
176
+		surface.getContext().getWindow().focus(this);
154 177
 	}
155 178
 	
156 179
 	@Override
@@ -197,11 +220,37 @@ public class DInputField implements DComponent {
197 220
 	private void setCursor(int from, int to) {
198 221
 		cursorFrom = from;
199 222
 		cursorTo = to;
200
-		context.repaint(bounds);
223
+		
224
+		int cursorXFrom = fontMetrics.getWidth(value.getValue(), 0, Math.min(cursorFrom, cursorTo));
225
+		int cursorXTo = fontMetrics.getWidth(value.getValue(), 0, Math.max(cursorFrom, cursorTo));
226
+		if (cursorFrom != cursorTo) {
227
+			selection.setRectangle(new DIRectangle(
228
+					bounds.x + style.margin.left + style.border.getPaddingLeft() + cursorXFrom,
229
+					bounds.y + style.margin.top + style.border.getPaddingTop(),
230
+					cursorXTo - cursorXFrom,
231
+					fontMetrics.getAscent() + fontMetrics.getDescent()));
232
+			selection.setColor(style.selectionColor);
233
+		} else {
234
+			selection.setColor(0);
235
+		}
236
+		
237
+		cursor.setRectangle(new DIRectangle(
238
+				bounds.x + style.margin.left + style.border.getPaddingLeft() + cursorXTo,
239
+				bounds.y + style.margin.top + style.border.getPaddingTop(),
240
+				style.cursorWidth,
241
+				fontMetrics.getAscent() + fontMetrics.getDescent()));
201 242
 	}
202 243
 	
203 244
 	private void handleValueUpdated(String newValue) {
204
-		context.repaint(bounds);
245
+		if (text != null)
246
+			text.close();
247
+		text = surface.drawText(
248
+				z + 2,
249
+				style.font,
250
+				style.color,
251
+				bounds.x + style.margin.left + style.border.getPaddingLeft(),
252
+				bounds.y + style.margin.top + style.border.getPaddingTop() + fontMetrics.getAscent(),
253
+				value.getValue());
205 254
 	}
206 255
 	
207 256
 	private void backspace() {

+ 6
- 19
DrawableGui/src/main/java/org/openzen/drawablegui/DInputFieldStyle.java View File

@@ -5,24 +5,18 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.border.DCompositeBorder;
9
+import org.openzen.drawablegui.border.DLineBorder;
10
+import org.openzen.drawablegui.border.DPaddedBorder;
11
+import org.openzen.drawablegui.style.DBaseStyle;
8 12
 import org.openzen.drawablegui.style.DDpDimension;
9
-import org.openzen.drawablegui.style.DPxDimension;
10 13
 import org.openzen.drawablegui.style.DStyleDefinition;
11 14
 
12 15
 /**
13 16
  *
14 17
  * @author Hoofdgebruiker
15 18
  */
16
-public class DInputFieldStyle {
17
-	public final int backgroundColor;
18
-	public final int paddingTop;
19
-	public final int paddingLeft;
20
-	public final int paddingRight;
21
-	public final int paddingBottom;
22
-	
23
-	public final int borderWidth;
24
-	public final int borderColor;
25
-	
19
+public class DInputFieldStyle extends DBaseStyle {
26 20
 	public final int color;
27 21
 	public final DFont font;
28 22
 	
@@ -32,14 +26,7 @@ public class DInputFieldStyle {
32 26
 	public final int selectionColor;
33 27
 	
34 28
 	public DInputFieldStyle(DStyleDefinition style) {
35
-		backgroundColor = style.getColor("backgroundColor", 0xFFFFFFFF);
36
-		paddingTop = style.getDimension("paddingTop", new DDpDimension(2));
37
-		paddingBottom = style.getDimension("paddingBottom", new DDpDimension(2));
38
-		paddingLeft = style.getDimension("paddingLeft", new DDpDimension(2));
39
-		paddingRight = style.getDimension("paddingRight", new DDpDimension(2));
40
-		
41
-		borderWidth = style.getDimension("borderWidth", new DPxDimension(1));
42
-		borderColor = style.getColor("borderColor", 0xFFABADB3);
29
+		super(style, context -> new DCompositeBorder(new DLineBorder(0xFFABADB3, 1), new DPaddedBorder(context.dp(2))), 0xFFFFFFFF);
43 30
 		
44 31
 		color = style.getColor("color", 0xFF000000);
45 32
 		font = style.getFont("font", context -> new DFont(DFontFamily.UI, false, false, false, (int)(14 * context.getScale())));

+ 38
- 12
DrawableGui/src/main/java/org/openzen/drawablegui/DLabel.java View File

@@ -5,6 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
+import org.openzen.drawablegui.draw.DDrawSurface;
9
+import org.openzen.drawablegui.draw.DDrawnText;
8 10
 import org.openzen.drawablegui.listeners.ListenerHandle;
9 11
 import org.openzen.drawablegui.live.LiveObject;
10 12
 import org.openzen.drawablegui.live.LiveString;
@@ -22,11 +24,14 @@ public class DLabel implements DComponent {
22 24
 	private final MutableLiveObject<DSizing> sizing = DSizing.create();
23 25
 	private final ListenerHandle<LiveString.Listener> labelListener;
24 26
 	
25
-	private DUIContext context;
27
+	private DDrawSurface surface;
28
+	private int z;
26 29
 	private DIRectangle bounds;
27 30
 	private DLabelStyle style;
28 31
 	private DFontMetrics fontMetrics;
29 32
 	
33
+	private DDrawnText text;
34
+	
30 35
 	public DLabel(DStyleClass styleClass, LiveString label) {
31 36
 		this.styleClass = styleClass;
32 37
 		this.label = label;
@@ -35,14 +40,27 @@ public class DLabel implements DComponent {
35 40
 	}
36 41
 
37 42
 	@Override
38
-	public void setContext(DStylePath parent, DUIContext context) {
39
-		this.context = context;
43
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
44
+		this.surface = surface;
45
+		this.z = z;
40 46
 		
41 47
 		DStylePath path = parent.getChild("label", styleClass);
42
-		style = new DLabelStyle(context.getStylesheets().get(context, path));
48
+		style = new DLabelStyle(surface.getStylesheet(path));
43 49
 		
44
-		fontMetrics = context.getFontMetrics(style.font);
50
+		fontMetrics = surface.getFontMetrics(style.font);
45 51
 		calculateDimension();
52
+		
53
+		if (text != null)
54
+			text.close();
55
+		text = surface.drawText(z, style.font, style.color, 0, 0, label.getValue());
56
+	}
57
+	
58
+	@Override
59
+	public void unmount() {
60
+		if (style != null)
61
+			style.border.close();
62
+		if (text != null)
63
+			text.close();
46 64
 	}
47 65
 
48 66
 	@Override
@@ -63,22 +81,30 @@ public class DLabel implements DComponent {
63 81
 	@Override
64 82
 	public void setBounds(DIRectangle bounds) {
65 83
 		this.bounds = bounds;
66
-	}
67
-
68
-	@Override
69
-	public void paint(DCanvas canvas) {
70
-		style.border.paint(canvas, bounds);
71
-		canvas.drawText(style.font, style.color, bounds.x + style.border.getPaddingLeft(), bounds.y + style.border.getPaddingTop() + fontMetrics.getAscent(), label.getValue());
84
+		style.border.update(surface, z + 1, bounds);
85
+		text.setPosition(
86
+				bounds.x + style.border.getPaddingLeft(),
87
+				bounds.y + style.border.getPaddingTop() + fontMetrics.getAscent());
72 88
 	}
73 89
 
74 90
 	@Override
75 91
 	public void close() {
76 92
 		labelListener.close();
93
+		unmount();
77 94
 	}
78 95
 	
79 96
 	private void onLabelChanged(String oldValue, String newValue) {
80 97
 		calculateDimension();
81
-		context.repaint(bounds);
98
+		
99
+		if (text != null)
100
+			text.close();
101
+		text = surface.drawText(
102
+				z,
103
+				style.font,
104
+				style.color,
105
+				bounds.x + style.border.getPaddingLeft(),
106
+				bounds.y + style.border.getPaddingTop() + fontMetrics.getAscent(),
107
+				newValue);
82 108
 	}
83 109
 	
84 110
 	private void calculateDimension() {

+ 49
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DPath.java View File

@@ -10,6 +10,13 @@ package org.openzen.drawablegui;
10 10
  * @author Hoofdgebruiker
11 11
  */
12 12
 public interface DPath {
13
+	public static DPath line(float x1, float y1, float x2, float y2) {
14
+		return tracer -> {
15
+			tracer.moveTo(x1, y1);
16
+			tracer.lineTo(x2, y2);
17
+		};
18
+	}
19
+	
13 20
 	public static DPath circle(float x, float y, float radius) {
14 21
 		// see http://spencermortensen.com/articles/bezier-circle/
15 22
 		return tracer -> {
@@ -45,6 +52,9 @@ public interface DPath {
45 52
 	}
46 53
 	
47 54
 	public static DPath roundedRectangle(float x, float y, float width, float height, float radius) {
55
+		if (radius < 0.01f)
56
+			return rectangle(x, y, width, height);
57
+		
48 58
 		return tracer -> {
49 59
 			float c = radius - radius * 0.551915024494f;
50 60
 			tracer.moveTo(x + width - radius, y + height);
@@ -71,5 +81,44 @@ public interface DPath {
71 81
 		};
72 82
 	}
73 83
 	
84
+	public static DPath roundedRectangle(float x, float y, float width, float height, float radiusTopLeft, float radiusTopRight, float radiusBottomLeft, float radiusBottomRight) {
85
+		return tracer -> {
86
+			float cTopLeft = radiusTopLeft - radiusTopLeft * 0.551915024494f;
87
+			float cTopRight = radiusTopRight - radiusTopRight * 0.551915024494f;
88
+			float cBottomLeft = radiusBottomLeft - radiusBottomLeft * 0.551915024494f;
89
+			float cBottomRight = radiusBottomRight - radiusBottomRight * 0.551915024494f;
90
+			
91
+			tracer.moveTo(x + width - radiusBottomRight, y + height);
92
+			if (radiusBottomRight > 0.01f) {
93
+				tracer.bezierCubic(
94
+						x + width - cBottomRight, y + height,
95
+						x + width, y + height - cBottomRight,
96
+						x + width, y + height - radiusBottomRight);
97
+			}
98
+			tracer.lineTo(x + width, y + radiusTopRight);
99
+			if (radiusTopRight > 0.01f) {
100
+				tracer.bezierCubic(
101
+						x + width, y + cTopRight,
102
+						x + width - cTopRight, y,
103
+						x + width - radiusTopRight, y);
104
+			}
105
+			tracer.lineTo(x + radiusTopLeft, y);
106
+			if (radiusTopLeft > 0.01f) {
107
+				tracer.bezierCubic(
108
+						x + cTopLeft, y,
109
+						x, y + cTopLeft,
110
+						x, y + radiusTopLeft);
111
+			}
112
+			tracer.lineTo(x, y + height - radiusBottomLeft);
113
+			if (radiusBottomLeft > 0.01f) {
114
+				tracer.bezierCubic(
115
+						x, y + height - cBottomLeft,
116
+						x + cBottomLeft, y + height,
117
+						x + radiusBottomLeft, y + height);
118
+			}
119
+			tracer.close();
120
+		};
121
+	}
122
+	
74 123
 	void trace(DPathTracer tracer);
75 124
 }

+ 24
- 48
DrawableGui/src/main/java/org/openzen/drawablegui/DSimpleTooltip.java View File

@@ -5,10 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui;
7 7
 
8
-import org.openzen.drawablegui.listeners.ListenerHandle;
9 8
 import org.openzen.drawablegui.live.LiveString;
10 9
 import org.openzen.drawablegui.style.DStyleClass;
11
-import org.openzen.drawablegui.style.DStylePath;
12 10
 
13 11
 /**
14 12
  *
@@ -17,31 +15,22 @@ import org.openzen.drawablegui.style.DStylePath;
17 15
 public class DSimpleTooltip {
18 16
 	private final DStyleClass styleClass;
19 17
 	private final LiveString tooltip;
20
-	private final ListenerHandle<LiveString.Listener> tooltipListener;
21 18
 	
22 19
 	private DUIContext context;
23
-	private DIRectangle bounds;
24
-	private DFontMetrics fontMetrics;
25
-	private DTooltipStyle style;
26
-	private boolean visible = false;
20
+	private DSimpleTooltipStyle style;
27 21
 	private DTimerHandle timerHandle = null;
28 22
 	
23
+	private int enterMouseX;
24
+	private int enterMouseY;
25
+	private DUIWindow window;
26
+	
29 27
 	public DSimpleTooltip(DStyleClass styleClass, LiveString tooltip) {
30 28
 		this.styleClass = styleClass;
31 29
 		this.tooltip = tooltip;
32
-		tooltipListener = tooltip.addListener(this::onTooltipChanged);
33 30
 	}
34 31
 	
35
-	private void onTooltipChanged(String oldValue, String newValue) {
36
-		if (context == null || bounds == null)
37
-			return;
38
-		
39
-		bounds = new DIRectangle(
40
-				bounds.x,
41
-				bounds.y,
42
-				style.border.getPaddingLeft() + fontMetrics.getWidth(tooltip.getValue()) + style.border.getPaddingRight(),
43
-				style.border.getPaddingTop() + fontMetrics.getAscent() + fontMetrics.getDescent() + style.border.getPaddingBottom());
44
-		context.repaint(bounds);
32
+	public void setContext(DUIContext context) {
33
+		this.context = context;
45 34
 	}
46 35
 	
47 36
 	public void onTargetMouseEnter(DMouseEvent e) {
@@ -49,11 +38,13 @@ public class DSimpleTooltip {
49 38
 			timerHandle.close();
50 39
 		
51 40
 		timerHandle = context.setTimer(1000, this::show);
52
-		bounds = new DIRectangle(
53
-				e.x,
54
-				e.y,
55
-				style.border.getPaddingLeft() + fontMetrics.getWidth(tooltip.getValue()) + style.border.getPaddingRight(),
56
-				style.border.getPaddingTop() + fontMetrics.getAscent() + fontMetrics.getDescent() + style.border.getPaddingBottom());
41
+		enterMouseX = e.x;
42
+		enterMouseY = e.y;
43
+	}
44
+	
45
+	public void onTargetMouseMove(DMouseEvent e) {
46
+		enterMouseX = e.x;
47
+		enterMouseY = e.y;
57 48
 	}
58 49
 	
59 50
 	public void onTargetMouseExit(DMouseEvent e) {
@@ -66,9 +57,8 @@ public class DSimpleTooltip {
66 57
 	}
67 58
 	
68 59
 	private void show() {
69
-		System.out.println("Show tooltip");
70
-		visible = true;
71
-		context.repaint(bounds);
60
+		DSimpleTooltipComponent view = new DSimpleTooltipComponent(styleClass, tooltip);
61
+		window = context.openView(enterMouseX, enterMouseY + context.dp(8), DAnchor.TOP_LEFT, view);
72 62
 		
73 63
 		if (timerHandle != null) {
74 64
 			timerHandle.close();
@@ -77,30 +67,16 @@ public class DSimpleTooltip {
77 67
 	}
78 68
 	
79 69
 	private void hide() {
80
-		System.out.println("Hide tooltip");
81
-		visible = false;
82
-		context.repaint(bounds);
83
-	}
84
-	
85
-	public void setContext(DStylePath parent, DUIContext context) {
86
-		this.context = context;
87
-		
88
-		DStylePath path = parent.getChild("tooltip", styleClass);
89
-		style = new DTooltipStyle(context.getStylesheets().get(context, path));
90
-		fontMetrics = context.getFontMetrics(style.font);
91
-	}
92
-	
93
-	public void paint(DCanvas canvas) {
94
-		if (!visible)
95
-			return;
96
-		
97
-		System.out.println("Actually paint tooltip");
98
-		canvas.fillRectangle(bounds.x, bounds.y, bounds.width, bounds.height, style.backgroundColor);
99
-		style.border.paint(canvas, bounds);
100
-		canvas.drawText(style.font, style.textColor, bounds.x + style.border.getPaddingLeft(), bounds.y + style.border.getPaddingTop(), tooltip.getValue());
70
+		if (window != null) {
71
+			window.close();
72
+			window = null;
73
+		}
101 74
 	}
102 75
 	
103 76
 	public void close() {
104
-		tooltipListener.close();
77
+		if (window != null) {
78
+			window.close();
79
+			window = null;
80
+		}
105 81
 	}
106 82
 }

+ 128
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/DSimpleTooltipComponent.java View File

@@ -0,0 +1,128 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui;
7
+
8
+import org.openzen.drawablegui.draw.DDrawSurface;
9
+import org.openzen.drawablegui.draw.DDrawnRectangle;
10
+import org.openzen.drawablegui.draw.DDrawnText;
11
+import org.openzen.drawablegui.listeners.ListenerHandle;
12
+import org.openzen.drawablegui.live.LiveObject;
13
+import org.openzen.drawablegui.live.LiveString;
14
+import org.openzen.drawablegui.live.MutableLiveObject;
15
+import org.openzen.drawablegui.style.DStyleClass;
16
+import org.openzen.drawablegui.style.DStylePath;
17
+
18
+/**
19
+ *
20
+ * @author Hoofdgebruiker
21
+ */
22
+public class DSimpleTooltipComponent implements DComponent {
23
+	private final DStyleClass styleClass;
24
+	private final LiveString tooltip;
25
+	private final MutableLiveObject<DSizing> sizing = DSizing.create();
26
+	private final ListenerHandle<LiveString.Listener> tooltipListener;
27
+	
28
+	private DDrawSurface surface;
29
+	private int z;
30
+	private DIRectangle bounds;
31
+	private DFontMetrics fontMetrics;
32
+	private DSimpleTooltipStyle style;
33
+	
34
+	private DDrawnRectangle background;
35
+	private DDrawnText text;
36
+	
37
+	public DSimpleTooltipComponent(DStyleClass styleClass, LiveString tooltip) {
38
+		this.styleClass = styleClass;
39
+		this.tooltip = tooltip;
40
+		tooltipListener = tooltip.addListener(this::onTooltipChanged);
41
+	}
42
+	
43
+	private void onTooltipChanged(String oldValue, String newValue) {
44
+		if (surface == null || bounds == null)
45
+			return;
46
+		
47
+		calculateSize();
48
+		bounds = new DIRectangle(
49
+				bounds.x,
50
+				bounds.y,
51
+				style.border.getPaddingLeft() + fontMetrics.getWidth(tooltip.getValue()) + style.border.getPaddingRight(),
52
+				style.border.getPaddingTop() + fontMetrics.getAscent() + fontMetrics.getDescent() + style.border.getPaddingBottom());
53
+		
54
+		if (text != null)
55
+			text.close();
56
+		
57
+		text = surface.drawText(
58
+				z,
59
+				style.font,
60
+				style.textColor,
61
+				bounds.x + style.border.getPaddingLeft(),
62
+				bounds.y + style.border.getPaddingTop() + fontMetrics.getAscent(),
63
+				newValue);
64
+	}
65
+	
66
+	@Override
67
+	public void setBounds(DIRectangle bounds) {
68
+		this.bounds = bounds;
69
+		style.border.update(surface, z + 1, bounds);
70
+		
71
+		if (background != null)
72
+			background.close();
73
+		background = surface.fillRect(z, bounds, style.backgroundColor);
74
+		text.setPosition(
75
+				bounds.x + style.border.getPaddingLeft(),
76
+				bounds.y + style.border.getPaddingTop() + fontMetrics.getAscent());
77
+	}
78
+	
79
+	@Override
80
+	public DIRectangle getBounds() {
81
+		return bounds;
82
+	}
83
+	
84
+	@Override
85
+	public int getBaselineY() {
86
+		return style.border.getPaddingTop() + fontMetrics.getAscent();
87
+	}
88
+	
89
+	@Override
90
+	public LiveObject<DSizing> getSizing() {
91
+		return sizing;
92
+	}
93
+	
94
+	@Override
95
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
96
+		this.surface = surface;
97
+		this.z = z;
98
+		
99
+		DStylePath path = parent.getChild("tooltip", styleClass);
100
+		style = new DSimpleTooltipStyle(surface.getStylesheet(path));
101
+		fontMetrics = surface.getFontMetrics(style.font);
102
+		calculateSize();
103
+		
104
+		if (text != null)
105
+			text.close();
106
+		text = surface.drawText(z + 1, style.font, style.textColor, 0, 0, tooltip.getValue());
107
+	}
108
+	
109
+	@Override
110
+	public void unmount() {
111
+		if (background != null)
112
+			background.close();
113
+		if (text != null)
114
+			text.close();
115
+	}
116
+	
117
+	@Override
118
+	public void close() {
119
+		tooltipListener.close();
120
+		unmount();
121
+	}
122
+	
123
+	private void calculateSize() {
124
+		sizing.setValue(new DSizing(
125
+				style.border.getPaddingLeft() + fontMetrics.getWidth(tooltip.getValue()) + style.border.getPaddingRight(),
126
+				style.border.getPaddingTop() + fontMetrics.getAscent() + fontMetrics.getDescent() + style.border.getPaddingBottom()));
127
+	}
128
+}

DrawableGui/src/main/java/org/openzen/drawablegui/DTooltipStyle.java → DrawableGui/src/main/java/org/openzen/drawablegui/DSimpleTooltipStyle.java View File

@@ -15,15 +15,15 @@ import org.openzen.drawablegui.style.DStyleDefinition;
15 15
  *
16 16
  * @author Hoofdgebruiker
17 17
  */
18
-public class DTooltipStyle {
18
+public class DSimpleTooltipStyle {
19 19
 	public final DBorder border;
20 20
 	public final DFont font;
21 21
 	public final int backgroundColor;
22 22
 	public final int textColor;
23 23
 	
24
-	public DTooltipStyle(DStyleDefinition style) {
24
+	public DSimpleTooltipStyle(DStyleDefinition style) {
25 25
 		border = style.getBorder("border", context -> new DCompositeBorder(
26
-				new DLineBorder(0xFF, 1),
26
+				new DLineBorder(0xFF000000, 1),
27 27
 				new DPaddedBorder(context.dp(4), context.dp(4), context.dp(4), context.dp(4))));
28 28
 		font = style.getFont("font", context -> new DFont(DFontFamily.UI, false, false, false, context.sp(12)));
29 29
 		backgroundColor = style.getColor("backgroundColor", 0xFFFFFFE1);

+ 0
- 26
DrawableGui/src/main/java/org/openzen/drawablegui/DTooltip.java View File

@@ -1,26 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui;
7
-
8
-import org.openzen.drawablegui.style.DStylePath;
9
-
10
-/**
11
- *
12
- * @author Hoofdgebruiker
13
- */
14
-public interface DTooltip {
15
-	void setContext(DUIContext context, DStylePath parent);
16
-	
17
-	int getWidth();
18
-	
19
-	int getHeight();
20
-	
21
-	void setBounds(DIRectangle bounds);
22
-	
23
-	DIRectangle getBounds();
24
-	
25
-	void paint(DCanvas canvas);
26
-}

+ 0
- 2
DrawableGui/src/main/java/org/openzen/drawablegui/DUIContext.java View File

@@ -40,8 +40,6 @@ public interface DUIContext {
40 40
 	
41 41
 	DUIWindow openView(int x, int y, DAnchor anchor, DComponent root);
42 42
 	
43
-	DTooltipHandle openTooltip(int x, int y, DTooltip tooltip);
44
-	
45 43
 	default int dp(float dp) {
46 44
 		return (int)(dp * getScale());
47 45
 	}

+ 1
- 1
DrawableGui/src/main/java/org/openzen/drawablegui/DUIWindow.java View File

@@ -13,7 +13,7 @@ import org.openzen.drawablegui.live.LiveObject;
13 13
  * @author Hoofdgebruiker
14 14
  */
15 15
 public interface DUIWindow {
16
-	DIRectangle getWindowBounds();
16
+	LiveObject<DIRectangle> getWindowBounds();
17 17
 	
18 18
 	DUIContext getContext();
19 19
 	

+ 0
- 274
DrawableGui/src/main/java/org/openzen/drawablegui/DVerticalLayout.java View File

@@ -1,274 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui;
7
-
8
-import java.util.function.Consumer;
9
-import java.util.function.Predicate;
10
-import org.openzen.drawablegui.listeners.ListenerHandle;
11
-import org.openzen.drawablegui.live.LiveObject;
12
-import org.openzen.drawablegui.live.MutableLiveObject;
13
-import org.openzen.drawablegui.live.SimpleLiveObject;
14
-import org.openzen.drawablegui.style.DStyleClass;
15
-import org.openzen.drawablegui.style.DStylePath;
16
-
17
-/**
18
- *
19
- * @author Hoofdgebruiker
20
- */
21
-public class DVerticalLayout extends BaseComponentGroup {
22
-	private final DStyleClass styleClass;
23
-	private final Alignment alignment;
24
-	private final Element[] components;
25
-	private final ListenerHandle<LiveObject.Listener<DSizing>>[] componentSizeListeners;
26
-	private final MutableLiveObject<DSizing> sizing = DSizing.create();
27
-	
28
-	private DUIContext context;
29
-	private DHorizontalLayoutStyle style;
30
-	private DIRectangle bounds;
31
-	private float totalGrow;
32
-	private float totalShrink;
33
-	
34
-	public DVerticalLayout(DStyleClass styleClass, Alignment alignment, Element... components) {
35
-		this.styleClass = styleClass;
36
-		this.alignment = alignment;
37
-		this.components = components;
38
-		
39
-		componentSizeListeners = new ListenerHandle[components.length];
40
-		totalGrow = 0;
41
-		totalShrink = 0;
42
-		
43
-		for (int i = 0; i < componentSizeListeners.length; i++) {
44
-			componentSizeListeners[i] = components[i].component.getSizing().addListener((oldValue, newValue) -> updateDimensionPreferences());
45
-			
46
-			totalGrow += components[i].grow;
47
-			totalShrink += components[i].shrink;
48
-		}
49
-	}
50
-
51
-	@Override
52
-	protected void forEachChild(Consumer<DComponent> children) {
53
-		for (Element element : components)
54
-			children.accept(element.component);
55
-	}
56
-
57
-	@Override
58
-	protected DComponent findChild(Predicate<DComponent> predicate) {
59
-		for (Element element : components)
60
-			if (predicate.test(element.component))
61
-				return element.component;
62
-		
63
-		return null;
64
-	}
65
-
66
-	@Override
67
-	public void setContext(DStylePath parent, DUIContext context) {
68
-		this.context = context;
69
-		
70
-		DStylePath path = parent.getChild("verticalLayout", styleClass);
71
-		style = new DHorizontalLayoutStyle(context.getStylesheets().get(context, path));
72
-		
73
-		for (Element element : components)
74
-			element.component.setContext(parent, context);
75
-		
76
-		layout();
77
-	}
78
-
79
-	@Override
80
-	public LiveObject<DSizing> getSizing() {
81
-		return sizing;
82
-	}
83
-
84
-	@Override
85
-	public DIRectangle getBounds() {
86
-		return bounds;
87
-	}
88
-
89
-	@Override
90
-	public int getBaselineY() {
91
-		return components[0].component.getBaselineY();
92
-	}
93
-
94
-	@Override
95
-	public void setBounds(DIRectangle bounds) {
96
-		this.bounds = bounds;
97
-		layout();
98
-	}
99
-
100
-	@Override
101
-	public void paint(DCanvas canvas) {
102
-		for (Element element : components) {
103
-			element.component.paint(canvas);
104
-		}
105
-	}
106
-
107
-	@Override
108
-	public void close() {
109
-		for (ListenerHandle<LiveObject.Listener<DSizing>> listener : componentSizeListeners) {
110
-			listener.close();
111
-		}
112
-	}
113
-	
114
-	public static enum Alignment {
115
-		TOP(0),
116
-		MIDDLE(0.5f),
117
-		BOTTOM(1);
118
-		
119
-		public final float align;
120
-		
121
-		Alignment(float align) {
122
-			this.align = align;
123
-		}
124
-	}
125
-	
126
-	public static enum ElementAlignment {
127
-		LEFT,
128
-		CENTER,
129
-		RIGHT,
130
-		STRETCH
131
-	}
132
-	
133
-	public static class Element {
134
-		public final DComponent component;
135
-		public final float grow;
136
-		public final float shrink;
137
-		public final ElementAlignment alignment;
138
-		
139
-		public Element(DComponent component, float grow, float shrink, ElementAlignment alignment) {
140
-			this.component = component;
141
-			this.grow = grow;
142
-			this.shrink = shrink;
143
-			this.alignment = alignment;
144
-		}
145
-	}
146
-	
147
-	private void layout() {
148
-		if (bounds == null || context == null)
149
-			return;
150
-		
151
-		DSizing myPreferences = sizing.getValue();
152
-		if (bounds.height < myPreferences.preferredHeight) {
153
-			layoutShrinked();
154
-		} else {
155
-			layoutGrown();
156
-		}
157
-	}
158
-	
159
-	private void layoutShrinked() {
160
-		DSizing myPreferences = sizing.getValue();
161
-		if (totalShrink == 0) {
162
-			// now what?
163
-			// shrink proportionally, we have to shrink...
164
-			float scale = (float)(bounds.height - (components.length - 1) * style.spacing) / (myPreferences.preferredHeight - (components.length - 1) * style.spacing);
165
-			int y = 0;
166
-			
167
-			for (int i = 0; i < components.length; i++) {
168
-				Element element = components[i];
169
-				DSizing preferences = element.component.getSizing().getValue();
170
-				int newY = y + preferences.preferredHeight;
171
-				float idealUnspacedY = newY * scale;
172
-				int idealY = (int)(idealUnspacedY + 0.5f + i * style.spacing);
173
-				layout(element, bounds.y + y, idealY - y);
174
-				y = idealY;
175
-			}
176
-		} else {
177
-			int delta = bounds.height - myPreferences.preferredHeight;
178
-			float deltaScaled = delta / totalShrink;
179
-			int y = bounds.y;
180
-			for (Element element : components) {
181
-				DSizing preferences = element.component.getSizing().getValue();
182
-				float scaledSize = preferences.preferredHeight + deltaScaled * element.shrink;
183
-				float idealUnspacedY = y + scaledSize;
184
-				int newY = (int)(idealUnspacedY + 0.5f);
185
-				layout(element, y, newY - y);
186
-				y = newY + style.spacing;
187
-			}
188
-		}
189
-	}
190
-	
191
-	private void layoutGrown() {
192
-		// resize according to grow values
193
-		DSizing myPreferences = sizing.getValue();
194
-		
195
-		if (totalGrow == 0) {
196
-			int deltaY = (int)(myPreferences.preferredHeight - bounds.height);
197
-			int y = bounds.y + (int)(deltaY * alignment.align);
198
-			for (Element element : components) {
199
-				DSizing preferences = element.component.getSizing().getValue();
200
-				int newY = y + preferences.preferredHeight;
201
-				layout(element, y, newY - y);
202
-				y = newY;
203
-			}
204
-		} else {
205
-			int delta = bounds.width - myPreferences.preferredWidth;
206
-			float deltaScaled = delta / totalGrow;
207
-			int y = bounds.y;
208
-			for (Element element : components) {
209
-				DSizing preferences = element.component.getSizing().getValue();
210
-				float scaledSize = preferences.preferredHeight + deltaScaled * element.grow;
211
-				float idealUnspacedY = y + scaledSize;
212
-				int newY = (int)(idealUnspacedY + 0.5f);
213
-				layout(element, y, newY - y);
214
-				y = newY + style.spacing;
215
-			}
216
-		}
217
-	}
218
-	
219
-	private void layout(Element element, int y, int height) {
220
-		DSizing preferences = element.component.getSizing().getValue();
221
-		int x;
222
-		int width;
223
-		switch (element.alignment) {
224
-			case LEFT:
225
-				width = Math.min(preferences.preferredWidth, bounds.width - style.paddingLeft - style.paddingRight);
226
-				x = bounds.x + style.paddingLeft;
227
-				break;
228
-			case CENTER:
229
-				width = Math.min(preferences.preferredWidth, bounds.width - style.paddingLeft - style.paddingRight);
230
-				x = bounds.x + style.paddingLeft + (bounds.width - style.paddingLeft - style.paddingRight - width) / 2;
231
-				break;
232
-			case RIGHT:
233
-				width = Math.min(preferences.preferredWidth, bounds.width - style.paddingLeft - style.paddingRight);
234
-				x = bounds.x + bounds.width - style.paddingLeft - width;
235
-				break;
236
-			case STRETCH:
237
-			default:
238
-				width = bounds.width - style.paddingLeft - style.paddingRight;
239
-				x = bounds.x + style.paddingLeft;
240
-				break;
241
-		}
242
-		element.component.setBounds(new DIRectangle(x, y, width, height));
243
-	}
244
-	
245
-	private void updateDimensionPreferences() {
246
-		int preferredWidth = 0;
247
-		int preferredHeight = -style.spacing;
248
-		int minimumWidth = 0;
249
-		int minimumHeight = -style.spacing;
250
-		int maximumWidth = Integer.MAX_VALUE;
251
-		int maximumHeight = -style.spacing;
252
-		
253
-		for (Element element : components) {
254
-			DSizing preferences = element.component.getSizing().getValue();
255
-			preferredWidth = Math.max(preferredWidth, preferences.preferredWidth);
256
-			preferredHeight += preferences.preferredHeight + style.spacing;
257
-			
258
-			minimumWidth = Math.max(minimumWidth, preferences.minimumWidth);
259
-			minimumHeight += preferences.minimumHeight + style.spacing;
260
-			
261
-			maximumWidth = Math.min(maximumWidth, preferences.maximumWidth);
262
-			maximumHeight += preferences.maximumHeight + style.spacing;
263
-		}
264
-		
265
-		DSizing preferences = new DSizing(
266
-				minimumWidth + style.paddingLeft + style.paddingRight,
267
-				minimumHeight + style.paddingTop + style.paddingBottom,
268
-				preferredWidth + style.paddingLeft + style.paddingRight,
269
-				preferredHeight + style.paddingTop + style.paddingBottom,
270
-				maximumWidth + style.paddingLeft + style.paddingRight,
271
-				maximumHeight + style.paddingTop + style.paddingBottom);
272
-		sizing.setValue(preferences);
273
-	}
274
-}

+ 0
- 31
DrawableGui/src/main/java/org/openzen/drawablegui/DVerticalLayoutStyle.java View File

@@ -1,31 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui;
7
-
8
-import org.openzen.drawablegui.style.DDpDimension;
9
-import org.openzen.drawablegui.style.DStyleDefinition;
10
-
11
-/**
12
- *
13
- * @author Hoofdgebruiker
14
- */
15
-public class DVerticalLayoutStyle {
16
-	public final int spacing;
17
-	
18
-	public final int paddingTop;
19
-	public final int paddingLeft;
20
-	public final int paddingRight;
21
-	public final int paddingBottom;
22
-	
23
-	public DVerticalLayoutStyle(DStyleDefinition style) {
24
-		spacing = style.getDimension("spacing", new DDpDimension(8));
25
-		
26
-		paddingTop = style.getDimension("paddingTop", new DDpDimension(8));
27
-		paddingLeft = style.getDimension("paddingLeft", new DDpDimension(8));
28
-		paddingRight = style.getDimension("paddingRight", new DDpDimension(8));
29
-		paddingBottom = style.getDimension("paddingBottom", new DDpDimension(8));
30
-	}
31
-}

+ 22
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/Destructible.java View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui;
7
+
8
+import java.util.List;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public interface Destructible extends AutoCloseable {
15
+	public static <T extends Destructible> void close(List<T> list) {
16
+		for (T item : list)
17
+			item.close();
18
+	}
19
+	
20
+	@Override
21
+	public void close();
22
+}

+ 15
- 3
DrawableGui/src/main/java/org/openzen/drawablegui/border/DBorder.java View File

@@ -5,15 +5,16 @@
5 5
  */
6 6
 package org.openzen.drawablegui.border;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
8
+import java.io.Closeable;
9 9
 import org.openzen.drawablegui.DIRectangle;
10
+import org.openzen.drawablegui.draw.DDrawSurface;
10 11
 
11 12
 /**
12 13
  *
13 14
  * @author Hoofdgebruiker
14 15
  */
15
-public interface DBorder {
16
-	public void paint(DCanvas canvas, DIRectangle bounds);
16
+public interface DBorder extends Closeable {
17
+	public void update(DDrawSurface surface, int z, DIRectangle bounds);
17 18
 	
18 19
 	public int getPaddingLeft();
19 20
 	
@@ -22,4 +23,15 @@ public interface DBorder {
22 23
 	public int getPaddingTop();
23 24
 	
24 25
 	public int getPaddingBottom();
26
+	
27
+	default int getPaddingHorizontal() {
28
+		return getPaddingLeft() + getPaddingRight();
29
+	}
30
+	
31
+	default int getPaddingVertical() {
32
+		return getPaddingTop() + getPaddingBottom();
33
+	}
34
+	
35
+	@Override
36
+	void close();
25 37
 }

+ 9
- 3
DrawableGui/src/main/java/org/openzen/drawablegui/border/DCompositeBorder.java View File

@@ -5,8 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui.border;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
9 8
 import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.draw.DDrawSurface;
10 10
 
11 11
 /**
12 12
  *
@@ -20,9 +20,9 @@ public class DCompositeBorder implements DBorder {
20 20
 	}
21 21
 
22 22
 	@Override
23
-	public void paint(DCanvas canvas, DIRectangle bounds) {
23
+	public void update(DDrawSurface surface, int z, DIRectangle bounds) {
24 24
 		for (DBorder border : borders) {
25
-			border.paint(canvas, bounds);
25
+			border.update(surface, z, bounds);
26 26
 			bounds = new DIRectangle(
27 27
 					bounds.x + border.getPaddingLeft(),
28 28
 					bounds.y + border.getPaddingTop(),
@@ -62,4 +62,10 @@ public class DCompositeBorder implements DBorder {
62 62
 			total += border.getPaddingBottom();
63 63
 		return total;
64 64
 	}
65
+	
66
+	@Override
67
+	public void close() {
68
+		for (DBorder border : borders)
69
+			border.close();
70
+	}
65 71
 }

+ 63
- 42
DrawableGui/src/main/java/org/openzen/drawablegui/border/DCustomWindowBorder.java View File

@@ -5,15 +5,16 @@
5 5
  */
6 6
 package org.openzen.drawablegui.border;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
9 8
 import org.openzen.drawablegui.DComponent;
10 9
 import org.openzen.drawablegui.DSizing;
11 10
 import org.openzen.drawablegui.DMouseEvent;
12 11
 import org.openzen.drawablegui.DPath;
13 12
 import org.openzen.drawablegui.DTransform2D;
14
-import org.openzen.drawablegui.DUIContext;
15 13
 import org.openzen.drawablegui.DUIWindow;
16 14
 import org.openzen.drawablegui.DIRectangle;
15
+import org.openzen.drawablegui.draw.DDrawSurface;
16
+import org.openzen.drawablegui.draw.DDrawnRectangle;
17
+import org.openzen.drawablegui.draw.DDrawnShape;
17 18
 import org.openzen.drawablegui.listeners.ListenerHandle;
18 19
 import org.openzen.drawablegui.live.ImmutableLiveObject;
19 20
 import org.openzen.drawablegui.live.LiveBool;
@@ -30,10 +31,10 @@ public class DCustomWindowBorder implements DComponent {
30 31
 	private final DComponent content;
31 32
 	private final LiveObject<DSizing> sizing = new ImmutableLiveObject<>(DSizing.EMPTY);
32 33
 	
33
-	private DUIContext context;
34
+	private DDrawSurface surface;
35
+	private int z;
34 36
 	private DCustomWindowBorderStyle style;
35 37
 	private DIRectangle bounds;
36
-	private DPath border;
37 38
 	
38 39
 	private LiveBool active;
39 40
 	private LiveObject<DUIWindow.State> state;
@@ -41,27 +42,42 @@ public class DCustomWindowBorder implements DComponent {
41 42
 	private ListenerHandle<LiveObject.Listener<DUIWindow.State>> stateListener;
42 43
 	private ListenerHandle<LiveBool.Listener> activeListener;
43 44
 	
45
+	private DDrawnRectangle background;
46
+	private DDrawnShape shadowedBackground;
47
+	private DDrawnShape border;
48
+	
44 49
 	public DCustomWindowBorder(DStyleClass styleClass, DComponent content) {
45 50
 		this.styleClass = styleClass;
46 51
 		this.content = content;
47 52
 	}
48 53
 
49 54
 	@Override
50
-	public void setContext(DStylePath parent, DUIContext context) {
51
-		this.context = context;
52
-		content.setContext(parent, context);
55
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
56
+		this.surface = surface;
57
+		this.z = z;
58
+		content.mount(parent, z + 1, surface);
53 59
 		
54
-		state = context.getWindow().getWindowState();
55
-		active = context.getWindow().getActive();
60
+		state = surface.getContext().getWindow().getWindowState();
61
+		active = surface.getContext().getWindow().getActive();
56 62
 		stateListener = state.addListener(this::onStateChanged);
57 63
 		activeListener = active.addListener(this::onActiveChanged);
58 64
 		
59 65
 		DStylePath path = parent.getChild("customwindowborder", styleClass);
60
-		style = new DCustomWindowBorderStyle(context.getStylesheets().get(context, path));
66
+		style = new DCustomWindowBorderStyle(surface.getStylesheet(path));
61 67
 		
62 68
 		if (bounds != null)
63 69
 			layout();
64 70
 	}
71
+	
72
+	@Override
73
+	public void unmount() {
74
+		if (background != null)
75
+			background.close();
76
+		if (shadowedBackground != null)
77
+			shadowedBackground.close();
78
+		if (border != null)
79
+			border.close();
80
+	}
65 81
 
66 82
 	@Override
67 83
 	public LiveObject<DSizing> getSizing() {
@@ -90,11 +106,19 @@ public class DCustomWindowBorder implements DComponent {
90 106
 			return;
91 107
 		
92 108
 		if (state.getValue() != DUIWindow.State.MAXIMIZED) {
93
-			border = DPath.rectangle(
94
-				bounds.x + style.padding,
95
-				bounds.y + style.padding,
96
-				bounds.width - 2 * style.padding - style.borderWidth,
97
-				bounds.height - 2 * style.padding - style.borderWidth);
109
+			DPath path = DPath.rectangle(
110
+					bounds.x + style.padding,
111
+					bounds.y + style.padding,
112
+					bounds.width - 2 * style.padding - style.borderWidth,
113
+					bounds.height - 2 * style.padding - style.borderWidth);
114
+			if (border != null)
115
+				border.close();
116
+			border = surface.strokePath(
117
+					z + 1,
118
+					path,
119
+					DTransform2D.IDENTITY,
120
+					active.getValue() ? style.focusedBorderColor : style.inactiveBorderColor,
121
+					style.borderWidth);
98 122
 			
99 123
 			int spacing = style.borderWidth + style.padding;
100 124
 			DIRectangle inner = new DIRectangle(
@@ -104,35 +128,31 @@ public class DCustomWindowBorder implements DComponent {
104 128
 					bounds.height - 2 * spacing);
105 129
 
106 130
 			content.setBounds(inner);
131
+			
132
+			if (shadowedBackground != null)
133
+				shadowedBackground.close();
134
+			if (background != null) {
135
+				background.close();
136
+				background = null;
137
+			}
138
+			shadowedBackground = surface.shadowPath(z, path, DTransform2D.IDENTITY, style.backgroundColor, style.shadow);
107 139
 		} else {
108 140
 			content.setBounds(bounds);
109
-		}
110
-		context.repaint(bounds);
111
-	}
112
-
113
-	@Override
114
-	public void paint(DCanvas canvas) {
115
-		if (state.getValue() != DUIWindow.State.MAXIMIZED) {
116
-			int spacing = style.borderWidth + style.padding;
117
-			DIRectangle canvasBounds = canvas.getBounds();
118
-			if (canvasBounds == null
119
-					|| canvasBounds.x < bounds.x + spacing
120
-					|| canvasBounds.y < bounds.y + spacing
121
-					|| canvasBounds.x + canvasBounds.width > bounds.x + bounds.width - spacing
122
-					|| canvasBounds.y + canvasBounds.height > bounds.y + bounds.height - spacing) {
123
-				canvas.shadowPath(border, DTransform2D.IDENTITY, style.shadow);
124
-				canvas.fillPath(border, DTransform2D.IDENTITY, style.backgroundColor);
125
-				canvas.strokePath(
126
-						border,
127
-						DTransform2D.IDENTITY,
128
-						active.getValue() ? style.focusedBorderColor : style.inactiveBorderColor,
129
-						style.borderWidth);
141
+			
142
+			if (shadowedBackground != null) {
143
+				shadowedBackground.close();
144
+				shadowedBackground = null;
145
+			}
146
+			if (border != null) {
147
+				border.close();
148
+				border = null;
149
+			}
150
+			if (background == null) {
151
+				background = surface.fillRect(z, bounds, style.backgroundColor);
152
+			} else {
153
+				background.setRectangle(bounds);
130 154
 			}
131
-		} else {
132
-			canvas.fillRectangle(bounds.x, bounds.y, bounds.width, bounds.height, style.backgroundColor);
133 155
 		}
134
-		
135
-		content.paint(canvas);
136 156
 	}
137 157
 
138 158
 	@Override
@@ -177,7 +197,7 @@ public class DCustomWindowBorder implements DComponent {
177 197
 	
178 198
 	@Override
179 199
 	public void close() {
180
-		
200
+		unmount();
181 201
 	}
182 202
 	
183 203
 	private void onStateChanged(DUIWindow.State oldValue, DUIWindow.State newValue) {
@@ -185,6 +205,7 @@ public class DCustomWindowBorder implements DComponent {
185 205
 	}
186 206
 	
187 207
 	private void onActiveChanged(boolean oldValue, boolean newValue) {
188
-		context.repaint(bounds);
208
+		if (border != null)
209
+			border.setColor(newValue ? style.focusedBorderColor : style.inactiveBorderColor);
189 210
 	}
190 211
 }

+ 9
- 2
DrawableGui/src/main/java/org/openzen/drawablegui/border/DEmptyBorder.java View File

@@ -5,8 +5,9 @@
5 5
  */
6 6
 package org.openzen.drawablegui.border;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
9 8
 import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.draw.DDrawSurface;
10
+import org.openzen.drawablegui.style.DBorderElement;
10 11
 
11 12
 /**
12 13
  *
@@ -14,11 +15,12 @@ import org.openzen.drawablegui.DIRectangle;
14 15
  */
15 16
 public class DEmptyBorder implements DBorder {
16 17
 	public static final DEmptyBorder INSTANCE = new DEmptyBorder();
18
+	public static final DBorderElement ELEMENT = context -> INSTANCE;
17 19
 	
18 20
 	private DEmptyBorder() {}
19 21
 	
20 22
 	@Override
21
-	public void paint(DCanvas canvas, DIRectangle bounds) {
23
+	public void update(DDrawSurface surface, int z, DIRectangle bounds) {
22 24
 		
23 25
 	}
24 26
 
@@ -41,4 +43,9 @@ public class DEmptyBorder implements DBorder {
41 43
 	public int getPaddingBottom() {
42 44
 		return 0;
43 45
 	}
46
+
47
+	@Override
48
+	public void close() {
49
+		
50
+	}
44 51
 }

+ 15
- 3
DrawableGui/src/main/java/org/openzen/drawablegui/border/DLineBorder.java View File

@@ -5,9 +5,10 @@
5 5
  */
6 6
 package org.openzen.drawablegui.border;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
9 8
 import org.openzen.drawablegui.DTransform2D;
10 9
 import org.openzen.drawablegui.DIRectangle;
10
+import org.openzen.drawablegui.draw.DDrawSurface;
11
+import org.openzen.drawablegui.draw.DDrawnShape;
11 12
 
12 13
 /**
13 14
  *
@@ -17,14 +18,19 @@ public class DLineBorder implements DBorder {
17 18
 	private final int color;
18 19
 	private final int borderWidth;
19 20
 	
21
+	private DDrawnShape shape;
22
+	
20 23
 	public DLineBorder(int color, int borderWidth) {
21 24
 		this.color = color;
22 25
 		this.borderWidth = borderWidth;
23 26
 	}
24 27
 
25 28
 	@Override
26
-	public void paint(DCanvas canvas, DIRectangle bounds) {
27
-		canvas.strokePath(tracer -> {
29
+	public void update(DDrawSurface surface, int z, DIRectangle bounds) {
30
+		if (shape != null)
31
+			shape.close();
32
+		
33
+		shape = surface.strokePath(z, tracer -> {
28 34
 				tracer.moveTo(bounds.x, bounds.y);
29 35
 				tracer.lineTo(bounds.x + bounds.width - borderWidth, bounds.y);
30 36
 				tracer.lineTo(bounds.x + bounds.width - borderWidth, bounds.y + bounds.height - borderWidth);
@@ -52,4 +58,10 @@ public class DLineBorder implements DBorder {
52 58
 	public int getPaddingBottom() {
53 59
 		return borderWidth;
54 60
 	}
61
+
62
+	@Override
63
+	public void close() {
64
+		if (shape != null)
65
+			shape.close();
66
+	}
55 67
 }

+ 11
- 2
DrawableGui/src/main/java/org/openzen/drawablegui/border/DPaddedBorder.java View File

@@ -5,8 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui.border;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
9 8
 import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.draw.DDrawSurface;
10 10
 
11 11
 /**
12 12
  *
@@ -24,9 +24,13 @@ public class DPaddedBorder implements DBorder {
24 24
 		this.right = right;
25 25
 		this.bottom = bottom;
26 26
 	}
27
+	
28
+	public DPaddedBorder(int size) {
29
+		this(size, size, size, size);
30
+	}
27 31
 
28 32
 	@Override
29
-	public void paint(DCanvas canvas, DIRectangle bounds) {
33
+	public void update(DDrawSurface surface, int z, DIRectangle bounds) {
30 34
 		// nothing to paint
31 35
 	}
32 36
 
@@ -49,4 +53,9 @@ public class DPaddedBorder implements DBorder {
49 53
 	public int getPaddingBottom() {
50 54
 		return bottom;
51 55
 	}
56
+
57
+	@Override
58
+	public void close() {
59
+		
60
+	}
52 61
 }

+ 107
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/border/DSideBorder.java View File

@@ -0,0 +1,107 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.border;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.DPath;
10
+import org.openzen.drawablegui.DTransform2D;
11
+import org.openzen.drawablegui.draw.DDrawSurface;
12
+import org.openzen.drawablegui.draw.DDrawnShape;
13
+
14
+/**
15
+ *
16
+ * @author Hoofdgebruiker
17
+ */
18
+public class DSideBorder implements DBorder {
19
+	public final int leftWidth;
20
+	public final int leftColor;
21
+	public final int topWidth;
22
+	public final int topColor;
23
+	public final int rightWidth;
24
+	public final int rightColor;
25
+	public final int bottomWidth;
26
+	public final int bottomColor;
27
+	
28
+	private DDrawnShape left;
29
+	private DDrawnShape top;
30
+	private DDrawnShape right;
31
+	private DDrawnShape bottom;
32
+	
33
+	public DSideBorder(
34
+			int leftWidth, int leftColor,
35
+			int topWidth, int topColor,
36
+			int rightWidth, int rightColor,
37
+			int bottomWidth, int bottomColor) {
38
+		this.leftWidth = leftWidth;
39
+		this.leftColor = leftColor;
40
+		this.topWidth = topWidth;
41
+		this.topColor = topColor;
42
+		this.rightWidth = rightWidth;
43
+		this.rightColor = rightColor;
44
+		this.bottomWidth = bottomWidth;
45
+		this.bottomColor = bottomColor;
46
+	}
47
+
48
+	@Override
49
+	public void update(DDrawSurface surface, int z, DIRectangle bounds) {
50
+		if (leftWidth > 0) {
51
+			int x = bounds.x;
52
+			if (left != null)
53
+				left.close();
54
+			left = surface.strokePath(z, DPath.line(x, bounds.y, x, bounds.y + bounds.height), DTransform2D.IDENTITY, topColor, topWidth);
55
+		}
56
+		if (topWidth > 0) {
57
+			int y = bounds.y;
58
+			if (top != null)
59
+				top.close();
60
+			top = surface.strokePath(z, DPath.line(bounds.x, y, bounds.x + bounds.width, y), DTransform2D.IDENTITY, topColor, topWidth);
61
+		}
62
+		if (rightWidth > 0) {
63
+			int x = bounds.x + bounds.width - rightWidth;
64
+			if (right != null)
65
+				right.close();
66
+			right = surface.strokePath(z, DPath.line(x, bounds.y, x, bounds.y + bounds.height), DTransform2D.IDENTITY, topColor, topWidth);
67
+		}
68
+		if (bottomWidth > 0) {
69
+			int y = bounds.y + bounds.height - bottomWidth;
70
+			if (bottom != null)
71
+				bottom.close();
72
+			bottom = surface.strokePath(z, DPath.line(bounds.x, y, bounds.x + bounds.width, y), DTransform2D.IDENTITY, topColor, topWidth);
73
+		}
74
+	}
75
+
76
+	@Override
77
+	public int getPaddingLeft() {
78
+		return leftWidth;
79
+	}
80
+
81
+	@Override
82
+	public int getPaddingRight() {
83
+		return rightWidth;
84
+	}
85
+
86
+	@Override
87
+	public int getPaddingTop() {
88
+		return topWidth;
89
+	}
90
+
91
+	@Override
92
+	public int getPaddingBottom() {
93
+		return bottomWidth;
94
+	}
95
+
96
+	@Override
97
+	public void close() {
98
+		if (left != null)
99
+			left.close();
100
+		if (top != null)
101
+			top.close();
102
+		if (right != null)
103
+			right.close();
104
+		if (bottom != null)
105
+			bottom.close();
106
+	}
107
+}

+ 22
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawSurface.java View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+import org.openzen.drawablegui.style.DStyleDefinition;
10
+import org.openzen.drawablegui.style.DStylePath;
11
+
12
+/**
13
+ *
14
+ * @author Hoofdgebruiker
15
+ */
16
+public interface DDrawSurface extends DDrawTarget {
17
+	DUIContext getContext();
18
+	
19
+	DStyleDefinition getStylesheet(DStylePath path);
20
+	
21
+	DSubSurface createSubSurface(int z);
22
+}

+ 37
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawTarget.java View File

@@ -0,0 +1,37 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+import org.openzen.drawablegui.DFont;
9
+import org.openzen.drawablegui.DFontMetrics;
10
+import org.openzen.drawablegui.DIRectangle;
11
+import org.openzen.drawablegui.DPath;
12
+import org.openzen.drawablegui.DTransform2D;
13
+import org.openzen.drawablegui.style.DShadow;
14
+
15
+/**
16
+ *
17
+ * @author Hoofdgebruiker
18
+ */
19
+public interface DDrawTarget {
20
+	public static final int INSTANCE_COLOR = 1;
21
+	
22
+	DFontMetrics getFontMetrics(DFont font);
23
+	
24
+	float getScale();
25
+	
26
+	float getTextScale();
27
+	
28
+	DDrawnText drawText(int z, DFont font, int color, float x, float y, String text);
29
+	
30
+	DDrawnRectangle fillRect(int z, DIRectangle rectangle, int color);
31
+	
32
+	DDrawnShape strokePath(int z, DPath path, DTransform2D transform, int color, float lineWidth);
33
+	
34
+	DDrawnShape fillPath(int z, DPath path, DTransform2D transform, int color);
35
+	
36
+	DDrawnShape shadowPath(int z, DPath path, DTransform2D transform, int color, DShadow shadow);
37
+}

+ 14
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnColorableElement.java View File

@@ -0,0 +1,14 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+/**
9
+ *
10
+ * @author Hoofdgebruiker
11
+ */
12
+public interface DDrawnColorableElement extends DDrawnElement {
13
+	void setColor(int color);
14
+}

+ 20
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnElement.java View File

@@ -0,0 +1,20 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.DTransform2D;
10
+import org.openzen.drawablegui.Destructible;
11
+
12
+/**
13
+ *
14
+ * @author Hoofdgebruiker
15
+ */
16
+public interface DDrawnElement extends Destructible {
17
+	void setTransform(DTransform2D transform);
18
+	
19
+	DIRectangle getBounds();
20
+}

+ 16
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnRectangle.java View File

@@ -0,0 +1,16 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public interface DDrawnRectangle extends DDrawnColorableElement {
15
+	void setRectangle(DIRectangle rectangle);
16
+}

DrawableGui/src/main/java/org/openzen/drawablegui/DTooltipHandle.java → DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnShape.java View File

@@ -3,12 +3,12 @@
3 3
  * To change this template file, choose Tools | Templates
4 4
  * and open the template in the editor.
5 5
  */
6
-package org.openzen.drawablegui;
6
+package org.openzen.drawablegui.draw;
7 7
 
8 8
 /**
9 9
  *
10 10
  * @author Hoofdgebruiker
11 11
  */
12
-public interface DTooltipHandle {
13
-	void close();
12
+public interface DDrawnShape extends DDrawnColorableElement {
13
+	
14 14
 }

+ 21
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DDrawnText.java View File

@@ -0,0 +1,21 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+import org.openzen.drawablegui.DTransform2D;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public interface DDrawnText extends DDrawnColorableElement {
15
+	@Override
16
+	default void setTransform(DTransform2D transform) { // only uses position, not scaling or rotation
17
+		setPosition(transform.xx, transform.yy);
18
+	}
19
+	
20
+	void setPosition(float x, float y);
21
+}

+ 24
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/draw/DSubSurface.java View File

@@ -0,0 +1,24 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.draw;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.DTransform2D;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public interface DSubSurface extends DDrawnElement, DDrawSurface {
16
+	@Override
17
+	default void setTransform(DTransform2D transform) {
18
+		setOffset((int)transform.xx, (int)transform.yy);
19
+	}
20
+	
21
+	void setOffset(int x, int y);
22
+	
23
+	void setClip(DIRectangle bounds);
24
+}

+ 42
- 25
DrawableGui/src/main/java/org/openzen/drawablegui/form/DForm.java View File

@@ -8,12 +8,12 @@ package org.openzen.drawablegui.form;
8 8
 import java.util.function.Consumer;
9 9
 import java.util.function.Predicate;
10 10
 import org.openzen.drawablegui.BaseComponentGroup;
11
-import org.openzen.drawablegui.DCanvas;
12 11
 import org.openzen.drawablegui.DComponent;
13 12
 import org.openzen.drawablegui.DSizing;
14 13
 import org.openzen.drawablegui.DFontMetrics;
15 14
 import org.openzen.drawablegui.DIRectangle;
16
-import org.openzen.drawablegui.DUIContext;
15
+import org.openzen.drawablegui.draw.DDrawSurface;
16
+import org.openzen.drawablegui.draw.DDrawnText;
17 17
 import org.openzen.drawablegui.live.LiveObject;
18 18
 import org.openzen.drawablegui.live.MutableLiveObject;
19 19
 import org.openzen.drawablegui.style.DStyleClass;
@@ -29,26 +29,31 @@ public class DForm extends BaseComponentGroup {
29 29
 	private final MutableLiveObject<DSizing> sizing = DSizing.create();
30 30
 	
31 31
 	private DIRectangle bounds;
32
-	private DUIContext context;
32
+	private DDrawSurface context;
33 33
 	private DFormStyle style;
34 34
 	private DFontMetrics fontMetrics;
35 35
 	private int maxFieldWidth;
36 36
 	private int maxLabelWidth;
37 37
 	
38
+	private final DDrawnText[] labels;
39
+	
38 40
 	public DForm(DStyleClass styleClass, DFormComponent... components) {
39 41
 		this.styleClass = styleClass;
40 42
 		this.components = components;
43
+		
44
+		labels = new DDrawnText[components.length];
41 45
 	}
42 46
 
43 47
 	@Override
44
-	public void setContext(DStylePath parent, DUIContext context) {
45
-		this.context = context;
48
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
49
+		this.context = surface;
46 50
 		
47 51
 		DStylePath path = parent.getChild("form", styleClass);
48
-		style = new DFormStyle(context.getStylesheets().get(context, path));
49
-		fontMetrics = context.getFontMetrics(style.labelFont);
52
+		style = new DFormStyle(surface.getStylesheet(path));
53
+		fontMetrics = surface.getFontMetrics(style.labelFont);
54
+		
50 55
 		for (DFormComponent component : components)
51
-			component.component.setContext(path, context);
56
+			component.component.mount(path, z + 1, surface);
52 57
 		
53 58
 		int height = style.paddingBottom + style.paddingTop;
54 59
 		int maxLabelWidth = style.minimumLabelSize;
@@ -71,6 +76,26 @@ public class DForm extends BaseComponentGroup {
71 76
 		
72 77
 		if (bounds != null)
73 78
 			layout();
79
+		
80
+		for (int i = 0; i < labels.length; i++) {
81
+			if (labels[i] != null)
82
+				labels[i].close();
83
+			labels[i] = surface.drawText(z + 1, style.labelFont, style.labelColor, 0, 0, components[i].label);
84
+		}
85
+	}
86
+	
87
+	@Override
88
+	public void unmount() {
89
+		for (int i = 0; i < labels.length; i++) {
90
+			if (labels[i] == null)
91
+				continue;
92
+			
93
+			labels[i].close();
94
+			labels[i] = null;
95
+		}
96
+		
97
+		for (DFormComponent component : components)
98
+			component.component.unmount();
74 99
 	}
75 100
 
76 101
 	@Override
@@ -97,35 +122,27 @@ public class DForm extends BaseComponentGroup {
97 122
 			layout();
98 123
 	}
99 124
 
100
-	@Override
101
-	public void paint(DCanvas canvas) {
102
-		int x = style.paddingLeft;
103
-		int y = style.paddingTop;
104
-		for (DFormComponent component : components) {
105
-			int baseline = component.component.getBaselineY();
106
-			if (baseline == -1)
107
-				baseline = fontMetrics.getAscent();
108
-			canvas.drawText(style.labelFont, style.labelColor, x, y + baseline, component.label);
109
-			component.component.paint(canvas);
110
-			
111
-			y += component.component.getSizing().getValue().preferredHeight + style.spacing;
112
-		}
113
-	}
114
-
115 125
 	@Override
116 126
 	public void close() {
117
-		
127
+		unmount();
118 128
 	}
119 129
 	
120 130
 	private void layout() {
121 131
 		int x = bounds.x + style.paddingLeft;
122 132
 		int y = bounds.y + style.paddingBottom;
123 133
 		
124
-		for (DFormComponent component : components) {
134
+		for (int i = 0; i < components.length; i++) {
135
+			DFormComponent component = components[i];
136
+			
125 137
 			int preferredHeight = component.component.getSizing().getValue().preferredHeight;
126 138
 			DIRectangle componentBounds = new DIRectangle(x + maxLabelWidth, y, bounds.width - maxLabelWidth - style.paddingLeft - style.paddingRight - style.spacing, preferredHeight);
127 139
 			component.component.setBounds(componentBounds);
128 140
 			
141
+			int baseline = component.component.getBaselineY();
142
+			if (baseline == -1)
143
+				baseline = fontMetrics.getAscent();
144
+			labels[i].setPosition(x, y + baseline);
145
+			
129 146
 			y += preferredHeight + style.spacing;
130 147
 		}
131 148
 	}

+ 463
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/layout/DLinearLayout.java View File

@@ -0,0 +1,463 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.layout;
7
+
8
+import java.util.function.Consumer;
9
+import java.util.function.Predicate;
10
+import org.openzen.drawablegui.BaseComponentGroup;
11
+import org.openzen.drawablegui.DComponent;
12
+import org.openzen.drawablegui.DIRectangle;
13
+import org.openzen.drawablegui.DSizing;
14
+import org.openzen.drawablegui.DTransform2D;
15
+import org.openzen.drawablegui.draw.DDrawSurface;
16
+import org.openzen.drawablegui.draw.DDrawnShape;
17
+import org.openzen.drawablegui.listeners.ListenerHandle;
18
+import org.openzen.drawablegui.live.LiveObject;
19
+import org.openzen.drawablegui.live.MutableLiveObject;
20
+import org.openzen.drawablegui.style.DStyleClass;
21
+import org.openzen.drawablegui.style.DStylePath;
22
+
23
+/**
24
+ *
25
+ * @author Hoofdgebruiker
26
+ */
27
+public class DLinearLayout extends BaseComponentGroup {
28
+	private final DStyleClass styleClass;
29
+	private final Orientation orientation;
30
+	private final Alignment alignment;
31
+	private final Element[] components;
32
+	private final ListenerHandle<LiveObject.Listener<DSizing>>[] componentSizeListeners;
33
+	private final MutableLiveObject<DSizing> sizing = DSizing.create();
34
+	
35
+	private DDrawSurface surface;
36
+	private int z;
37
+	private DLinearLayoutStyle style;
38
+	private DIRectangle bounds;
39
+	private float totalGrow;
40
+	private float totalShrink;
41
+	private DDrawnShape shape;
42
+	
43
+	public DLinearLayout(DStyleClass styleClass, Orientation orientation, Alignment alignment, Element... components) {
44
+		this.styleClass = styleClass;
45
+		this.orientation = orientation;
46
+		this.alignment = alignment;
47
+		this.components = components;
48
+		
49
+		componentSizeListeners = new ListenerHandle[components.length];
50
+		totalGrow = 0;
51
+		totalShrink = 0;
52
+		
53
+		for (int i = 0; i < componentSizeListeners.length; i++) {
54
+			componentSizeListeners[i] = components[i].component.getSizing().addListener((oldValue, newValue) -> updateSizing());
55
+			
56
+			totalGrow += components[i].grow;
57
+			totalShrink += components[i].shrink;
58
+		}
59
+	}
60
+
61
+	@Override
62
+	protected void forEachChild(Consumer<DComponent> children) {
63
+		for (Element element : components)
64
+			children.accept(element.component);
65
+	}
66
+
67
+	@Override
68
+	protected DComponent findChild(Predicate<DComponent> predicate) {
69
+		for (Element element : components)
70
+			if (predicate.test(element.component))
71
+				return element.component;
72
+		
73
+		return null;
74
+	}
75
+
76
+	@Override
77
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
78
+		this.surface = surface;
79
+		this.z = z;
80
+		
81
+		DStylePath path = parent.getChild("linearlayout", styleClass);
82
+		style = new DLinearLayoutStyle(surface.getStylesheet(path));
83
+		
84
+		for (Element element : components)
85
+			element.component.mount(parent, z + 1, surface);
86
+	}
87
+	
88
+	@Override
89
+	public void unmount() {
90
+		for (Element element : components)
91
+			element.component.unmount();
92
+	}
93
+
94
+	@Override
95
+	public LiveObject<DSizing> getSizing() {
96
+		return sizing;
97
+	}
98
+
99
+	@Override
100
+	public DIRectangle getBounds() {
101
+		return bounds;
102
+	}
103
+
104
+	@Override
105
+	public int getBaselineY() {
106
+		return components[0].component.getBaselineY();
107
+	}
108
+
109
+	@Override
110
+	public void setBounds(DIRectangle bounds) {
111
+		if (bounds.equals(this.bounds))
112
+			return;
113
+		
114
+		this.bounds = bounds;
115
+		style.border.update(surface, z + 1, bounds);
116
+		
117
+		if (shape != null)
118
+			shape.close();
119
+		shape = surface.shadowPath(z, style.shape.instance(style.margin.apply(bounds)), DTransform2D.IDENTITY, style.backgroundColor, style.shadow);
120
+		
121
+		layout();
122
+	}
123
+
124
+	@Override
125
+	public void close() {
126
+		for (ListenerHandle<LiveObject.Listener<DSizing>> listener : componentSizeListeners) {
127
+			listener.close();
128
+		}
129
+		for (Element element : components)
130
+			element.component.close();
131
+	}
132
+	
133
+	private int getInnerWidth() {
134
+		return bounds.width - style.margin.getHorizontal() - style.border.getPaddingHorizontal();
135
+	}
136
+	
137
+	private int getInnerHeight() {
138
+		return bounds.height - style.margin.getVertical() - style.border.getPaddingVertical();
139
+	}
140
+	
141
+	private int getPreferredInnerWidth() {
142
+		DSizing myPreferences = sizing.getValue();
143
+		return myPreferences.preferredWidth - style.margin.getHorizontal() - style.border.getPaddingHorizontal();
144
+	}
145
+	
146
+	private int getPreferredInnerHeight() {
147
+		DSizing myPreferences = sizing.getValue();
148
+		return myPreferences.preferredHeight - style.margin.getVertical() - style.border.getPaddingVertical();
149
+	}
150
+	
151
+	private void layout() {
152
+		if (orientation == Orientation.HORIZONTAL) {
153
+			layoutHorizontal();
154
+		} else {
155
+			layoutVertical();
156
+		}
157
+	}
158
+	
159
+	private void layoutHorizontal() {
160
+		if (bounds == null || surface == null)
161
+			return;
162
+		
163
+		DSizing myPreferences = sizing.getValue();
164
+		if (bounds.width < myPreferences.preferredWidth) {
165
+			layoutHorizontalShrinked();
166
+		} else {
167
+			layoutHorizontalGrown();
168
+		}
169
+	}
170
+	
171
+	private void layoutVertical() {
172
+		if (bounds == null || surface == null)
173
+			return;
174
+		
175
+		DSizing myPreferences = sizing.getValue();
176
+		if (bounds.height < myPreferences.preferredHeight) {
177
+			layoutVerticalShrinked();
178
+		} else {
179
+			layoutVerticalGrown();
180
+		}
181
+	}
182
+	
183
+	private void layoutHorizontalShrinked() {
184
+		float availableWidth = getInnerWidth() - (components.length - 1) * style.spacing;
185
+		float preferredInnerWidth = getPreferredInnerWidth() - (components.length - 1) * style.spacing;
186
+		
187
+		if (totalShrink == 0) {
188
+			// now what?
189
+			// shrink proportionally, we have to shrink...
190
+			float scale = availableWidth / preferredInnerWidth;
191
+			int x = bounds.x + style.margin.left + style.border.getPaddingLeft();
192
+			
193
+			for (Element element : components) {
194
+				DSizing preferences = element.component.getSizing().getValue();
195
+				int newX = (int)(x + preferences.preferredWidth * scale + 0.5f);
196
+				layoutHorizontal(element, bounds.x + x, newX - x);
197
+				x = newX + style.spacing;
198
+			}
199
+		} else {
200
+			int delta = getInnerHeight() - getPreferredInnerHeight();
201
+			float deltaScaled = delta / totalShrink;
202
+			int y = bounds.y;
203
+			for (Element element : components) {
204
+				DSizing preferences = element.component.getSizing().getValue();
205
+				float scaledSize = preferences.preferredHeight + deltaScaled * element.shrink;
206
+				float idealUnspacedY = y + scaledSize;
207
+				int newX = (int)(idealUnspacedY + 0.5f);
208
+				layoutHorizontal(element, y, newX - y);
209
+				y = newX + style.spacing;
210
+			}
211
+		}
212
+	}
213
+	
214
+	private void layoutVerticalShrinked() {
215
+		float availableHeight = getInnerHeight() - (components.length - 1) * style.spacing;
216
+		float preferredInnerHeight = getPreferredInnerHeight() - (components.length - 1) * style.spacing;
217
+		
218
+		if (totalShrink == 0) {
219
+			// now what?
220
+			// shrink proportionally, we have to shrink...
221
+			float scale = availableHeight / preferredInnerHeight;
222
+			int y = bounds.y + style.margin.top + style.border.getPaddingTop();
223
+			
224
+			for (int i = 0; i < components.length; i++) {
225
+				Element element = components[i];
226
+				DSizing preferences = element.component.getSizing().getValue();
227
+				int newY = (int)(y + preferences.preferredHeight * scale + 0.5f);
228
+				layoutVertical(element, bounds.y + y, newY - y);
229
+				y = newY + style.spacing;
230
+			}
231
+		} else {
232
+			int delta = getInnerHeight() - getPreferredInnerHeight();
233
+			float deltaScaled = delta / totalShrink;
234
+			int y = bounds.y;
235
+			for (Element element : components) {
236
+				DSizing preferences = element.component.getSizing().getValue();
237
+				float scaledSize = preferences.preferredHeight + deltaScaled * element.shrink;
238
+				float idealUnspacedY = y + scaledSize;
239
+				int newY = (int)(idealUnspacedY + 0.5f);
240
+				layoutVertical(element, y, newY - y);
241
+				y = newY + style.spacing;
242
+			}
243
+		}
244
+	}
245
+	
246
+	private void layoutHorizontalGrown() {
247
+		// resize according to grow values
248
+		int delta = getPreferredInnerWidth() - getInnerWidth();
249
+		if (totalGrow == 0) {
250
+			int x = bounds.x + style.margin.left + style.border.getPaddingLeft() + (int)(delta * alignment.align);
251
+			for (Element element : components) {
252
+				DSizing preferences = element.component.getSizing().getValue();
253
+				int newX = x + preferences.preferredWidth;
254
+				layoutHorizontal(element, x, newX - x);
255
+				x = newX;
256
+			}
257
+		} else {
258
+			float deltaScaled = delta / totalGrow;
259
+			int x = bounds.x + style.margin.left + style.border.getPaddingLeft();
260
+			for (Element element : components) {
261
+				DSizing preferences = element.component.getSizing().getValue();
262
+				float scaledSize = preferences.preferredWidth - deltaScaled * element.grow;
263
+				float idealUnspacedX = x + scaledSize;
264
+				int newX = (int)(idealUnspacedX + 0.5f);
265
+				layoutHorizontal(element, x, newX - x);
266
+				x = newX + style.spacing;
267
+			}
268
+		}
269
+	}
270
+	
271
+	private void layoutVerticalGrown() {
272
+		// resize according to grow values
273
+		int delta = getPreferredInnerHeight() - getInnerHeight();
274
+		if (totalGrow == 0) {
275
+			int y = bounds.y + style.margin.top + style.border.getPaddingTop() + (int)(delta * alignment.align);
276
+			for (Element element : components) {
277
+				DSizing preferences = element.component.getSizing().getValue();
278
+				int newY = y + preferences.preferredHeight;
279
+				layoutVertical(element, y, newY - y);
280
+				y = newY;
281
+			}
282
+		} else {
283
+			float deltaScaled = delta / totalGrow;
284
+			int y = bounds.y + style.margin.top + style.border.getPaddingTop();
285
+			for (Element element : components) {
286
+				DSizing preferences = element.component.getSizing().getValue();
287
+				float scaledSize = preferences.preferredHeight - deltaScaled * element.grow;
288
+				float idealUnspacedY = y + scaledSize;
289
+				int newY = (int)(idealUnspacedY + 0.5f);
290
+				layoutVertical(element, y, newY - y);
291
+				y = newY + style.spacing;
292
+			}
293
+		}
294
+	}
295
+	
296
+	private void layoutHorizontal(Element element, int x, int width) {
297
+		DSizing preferences = element.component.getSizing().getValue();
298
+		int height;
299
+		int y;
300
+		switch (element.alignment) {
301
+			case BOTTOM:
302
+				height = Math.min(preferences.preferredHeight, bounds.height - style.border.getPaddingVertical());
303
+				y = bounds.y + style.border.getPaddingTop();
304
+				break;
305
+			case MIDDLE:
306
+				height = Math.min(preferences.preferredHeight, bounds.height - style.border.getPaddingVertical());
307
+				y = bounds.y + style.border.getPaddingTop() + (bounds.height - style.border.getPaddingVertical() - height) / 2;
308
+				break;
309
+			case TOP:
310
+				height = Math.min(preferences.preferredHeight, bounds.height - style.border.getPaddingVertical());
311
+				y = bounds.y + bounds.height - style.border.getPaddingBottom() - height;
312
+				break;
313
+			case STRETCH:
314
+			default:
315
+				height = bounds.height - style.border.getPaddingVertical();
316
+				y = bounds.y + style.border.getPaddingTop();
317
+				break;
318
+		}
319
+		element.component.setBounds(new DIRectangle(x, y, width, height));
320
+	}
321
+	
322
+	private void layoutVertical(Element element, int y, int height) {
323
+		DSizing preferences = element.component.getSizing().getValue();
324
+		int x;
325
+		int width;
326
+		switch (element.alignment) {
327
+			case LEFT:
328
+				width = Math.min(preferences.preferredWidth, bounds.width - style.border.getPaddingHorizontal() - style.margin.getHorizontal());
329
+				x = bounds.x + style.margin.left + style.border.getPaddingLeft();
330
+				break;
331
+			case CENTER:
332
+				width = Math.min(preferences.preferredWidth, bounds.width - style.border.getPaddingHorizontal());
333
+				x = bounds.x + style.margin.left + style.border.getPaddingLeft() + (bounds.width - style.border.getPaddingHorizontal() - width) / 2;
334
+				break;
335
+			case RIGHT:
336
+				width = Math.min(preferences.preferredWidth, bounds.width - style.border.getPaddingHorizontal());
337
+				x = bounds.x + bounds.width - style.margin.right - style.border.getPaddingRight() - width;
338
+				break;
339
+			case STRETCH:
340
+			default:
341
+				width = bounds.width - style.border.getPaddingHorizontal() - style.margin.getHorizontal();
342
+				x = bounds.x + style.margin.left + style.border.getPaddingLeft();
343
+				break;
344
+		}
345
+		element.component.setBounds(new DIRectangle(x, y, width, height));
346
+	}
347
+	
348
+	private void updateSizing() {
349
+		if (orientation == Orientation.HORIZONTAL) {
350
+			updateSizingHorizontal();
351
+		} else {
352
+			updateSizingVertical();
353
+		}
354
+	}
355
+	
356
+	private void updateSizingHorizontal() {
357
+		int preferredWidth = -style.spacing;
358
+		int preferredHeight = 0;
359
+		int minimumWidth = -style.spacing;
360
+		int minimumHeight = Integer.MAX_VALUE;
361
+		int maximumWidth = -style.spacing;
362
+		int maximumHeight = 0;
363
+		
364
+		for (Element element : components) {
365
+			DSizing preferences = element.component.getSizing().getValue();
366
+			preferredWidth += preferences.preferredWidth + style.spacing;
367
+			preferredHeight = Math.max(preferredHeight, preferences.preferredHeight);
368
+			
369
+			minimumWidth += preferences.minimumWidth + style.spacing;
370
+			minimumHeight = Math.max(minimumHeight, preferences.minimumHeight);
371
+			
372
+			maximumHeight += preferences.maximumWidth + style.spacing;
373
+			maximumWidth = Math.min(maximumHeight, preferences.maximumHeight);
374
+		}
375
+		
376
+		int paddingHorizontal = style.border.getPaddingHorizontal() + style.margin.getHorizontal();
377
+		int paddingVertical = style.border.getPaddingVertical() + style.margin.getVertical();
378
+		DSizing preferences = new DSizing(
379
+				minimumWidth + paddingHorizontal,
380
+				minimumHeight + paddingVertical,
381
+				preferredWidth + paddingHorizontal,
382
+				preferredHeight + paddingVertical,
383
+				maximumWidth + paddingHorizontal,
384
+				maximumHeight + paddingVertical);
385
+		sizing.setValue(preferences);
386
+	}
387
+	
388
+	private void updateSizingVertical() {
389
+		int preferredWidth = 0;
390
+		int preferredHeight = -style.spacing;
391
+		int minimumWidth = 0;
392
+		int minimumHeight = -style.spacing;
393
+		int maximumWidth = Integer.MAX_VALUE;
394
+		int maximumHeight = -style.spacing;
395
+		
396
+		for (Element element : components) {
397
+			DSizing preferences = element.component.getSizing().getValue();
398
+			preferredWidth = Math.max(preferredWidth, preferences.preferredWidth);
399
+			preferredHeight += preferences.preferredHeight + style.spacing;
400
+			
401
+			minimumWidth = Math.max(minimumWidth, preferences.minimumWidth);
402
+			minimumHeight += preferences.minimumHeight + style.spacing;
403
+			
404
+			maximumWidth = Math.min(maximumWidth, preferences.maximumWidth);
405
+			maximumHeight += preferences.maximumHeight + style.spacing;
406
+		}
407
+		
408
+		int paddingHorizontal = style.border.getPaddingHorizontal() + style.margin.getHorizontal();
409
+		int paddingVertical = style.border.getPaddingVertical() + style.margin.getVertical();
410
+		DSizing preferences = new DSizing(
411
+				minimumWidth + paddingHorizontal,
412
+				minimumHeight + paddingVertical,
413
+				preferredWidth + paddingHorizontal,
414
+				preferredHeight + paddingVertical,
415
+				maximumWidth + paddingHorizontal,
416
+				maximumHeight + paddingVertical);
417
+		sizing.setValue(preferences);
418
+	}
419
+	
420
+	public static enum Orientation {
421
+		HORIZONTAL,
422
+		VERTICAL
423
+	}
424
+	
425
+	public static enum Alignment {
426
+		TOP(0),
427
+		LEFT(0),
428
+		MIDDLE(0.5f),
429
+		CENTER(0.5f),
430
+		BOTTOM(1),
431
+		RIGHT(1);
432
+		
433
+		public final float align;
434
+		
435
+		Alignment(float align) {
436
+			this.align = align;
437
+		}
438
+	}
439
+	
440
+	public static enum ElementAlignment {
441
+		LEFT,
442
+		CENTER,
443
+		RIGHT,
444
+		TOP,
445
+		MIDDLE,
446
+		BOTTOM,
447
+		STRETCH
448
+	}
449
+	
450
+	public static class Element {
451
+		public final DComponent component;
452
+		public final float grow;
453
+		public final float shrink;
454
+		public final ElementAlignment alignment;
455
+		
456
+		public Element(DComponent component, float grow, float shrink, ElementAlignment alignment) {
457
+			this.component = component;
458
+			this.grow = grow;
459
+			this.shrink = shrink;
460
+			this.alignment = alignment;
461
+		}
462
+	}
463
+}

+ 24
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/layout/DLinearLayoutStyle.java View File

@@ -0,0 +1,24 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.layout;
7
+
8
+import org.openzen.drawablegui.style.DBaseStyle;
9
+import org.openzen.drawablegui.style.DDpDimension;
10
+import org.openzen.drawablegui.style.DStyleDefinition;
11
+
12
+/**
13
+ *
14
+ * @author Hoofdgebruiker
15
+ */
16
+public class DLinearLayoutStyle extends DBaseStyle {
17
+	public final int spacing;
18
+	
19
+	public DLinearLayoutStyle(DStyleDefinition style) {
20
+		super(style);
21
+		
22
+		spacing = style.getDimension("spacing", new DDpDimension(8));
23
+	}
24
+}

DrawableGui/src/main/java/org/openzen/drawablegui/DSideLayout.java → DrawableGui/src/main/java/org/openzen/drawablegui/layout/DSideLayout.java View File

@@ -3,17 +3,22 @@
3 3
  * To change this template file, choose Tools | Templates
4 4
  * and open the template in the editor.
5 5
  */
6
-package org.openzen.drawablegui;
6
+package org.openzen.drawablegui.layout;
7 7
 
8 8
 import java.io.Closeable;
9 9
 import java.util.ArrayList;
10 10
 import java.util.List;
11 11
 import java.util.function.Consumer;
12 12
 import java.util.function.Predicate;
13
+import org.openzen.drawablegui.BaseComponentGroup;
14
+import org.openzen.drawablegui.DComponent;
15
+import org.openzen.drawablegui.DIRectangle;
16
+import org.openzen.drawablegui.DSizing;
17
+import org.openzen.drawablegui.draw.DDrawSurface;
18
+import org.openzen.drawablegui.draw.DDrawnRectangle;
13 19
 import org.openzen.drawablegui.listeners.ListenerHandle;
14 20
 import org.openzen.drawablegui.live.LiveObject;
15 21
 import org.openzen.drawablegui.live.MutableLiveObject;
16
-import org.openzen.drawablegui.live.SimpleLiveObject;
17 22
 import org.openzen.drawablegui.style.DStyleClass;
18 23
 import org.openzen.drawablegui.style.DStylePath;
19 24
 
@@ -29,17 +34,21 @@ public class DSideLayout extends BaseComponentGroup {
29 34
 	private final MutableLiveObject<DSizing> sizing = DSizing.create();
30 35
 	
31 36
 	private DStylePath path;
32
-	private DUIContext context;
37
+	private DDrawSurface surface;
38
+	private int z;
39
+	private DSideLayoutStyle style;
33 40
 	private DIRectangle bounds;
34 41
 	
42
+	private DDrawnRectangle background;
43
+	
35 44
 	public DSideLayout(DStyleClass styleClass, DComponent main) {
36 45
 		this.styleClass = styleClass;
37 46
 		this.main = main;
38 47
 	}
39 48
 	
40 49
 	public void add(Side side, DComponent component) {
41
-		if (context != null)
42
-			component.setContext(path, context);
50
+		if (surface != null)
51
+			component.mount(path, z + 1, surface);
43 52
 		
44 53
 		sides.add(new SideComponent(side, component));
45 54
 	}
@@ -50,21 +59,36 @@ public class DSideLayout extends BaseComponentGroup {
50 59
 		
51 60
 		this.main = component;
52 61
 		
53
-		if (context != null && bounds != null) {
54
-			main.setContext(path, context);
62
+		if (surface != null && bounds != null) {
63
+			main.mount(path, z + 1, surface);
55 64
 			setBounds(bounds);
56
-			context.repaint(bounds);
57 65
 		}
58 66
 	}
59 67
 
60 68
 	@Override
61
-	public void setContext(DStylePath parent, DUIContext context) {
62
-		this.context = context;
69
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
70
+		this.surface = surface;
71
+		this.z = z;
63 72
 		this.path = parent.getChild("sidelayout", styleClass);
73
+		style = new DSideLayoutStyle(surface.getStylesheet(path));
64 74
 		
65
-		main.setContext(path, context);
75
+		main.mount(path, z + 1, surface);
66 76
 		for (SideComponent side : sides)
67
-			side.component.setContext(path, context);
77
+			side.component.mount(path, z + 1, surface);
78
+		
79
+		if (background != null)
80
+			background.close();
81
+		background = surface.fillRect(z, DIRectangle.EMPTY, style.backgroundColor);
82
+	}
83
+	
84
+	@Override
85
+	public void unmount() {
86
+		main.unmount();
87
+		for (SideComponent side : sides)
88
+			side.component.unmount();
89
+		
90
+		background.close();
91
+		background = null;
68 92
 	}
69 93
 	
70 94
 	@Override
@@ -92,6 +116,8 @@ public class DSideLayout extends BaseComponentGroup {
92 116
 	public void setBounds(DIRectangle bounds) {
93 117
 		this.bounds = bounds;
94 118
 		
119
+		background.setRectangle(bounds);
120
+		
95 121
 		int left = bounds.x;
96 122
 		int right = bounds.x + bounds.width;
97 123
 		int top = bounds.y;
@@ -166,14 +192,6 @@ public class DSideLayout extends BaseComponentGroup {
166 192
 		
167 193
 		main.setBounds(new DIRectangle(left, top, right - left, bottom - top));
168 194
 	}
169
-
170
-	@Override
171
-	public void paint(DCanvas canvas) {
172
-		main.paint(canvas);
173
-		
174
-		for (SideComponent component : sides)
175
-			component.component.paint(canvas);
176
-	}
177 195
 	
178 196
 	private void recalculateSize() {
179 197
 		DSizing mainPreferences = main.getSizing().getValue();
@@ -240,6 +258,8 @@ public class DSideLayout extends BaseComponentGroup {
240 258
 		main.close();
241 259
 		for (SideComponent side : sides)
242 260
 			side.close();
261
+		
262
+		background.close();
243 263
 	}
244 264
 	
245 265
 	public class SideComponent implements Closeable, LiveObject.Listener<DSizing> {

+ 20
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/layout/DSideLayoutStyle.java View File

@@ -0,0 +1,20 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.layout;
7
+
8
+import org.openzen.drawablegui.style.DStyleDefinition;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public class DSideLayoutStyle {
15
+	public final int backgroundColor;
16
+	
17
+	public DSideLayoutStyle(DStyleDefinition style) {
18
+		backgroundColor = style.getColor("backgroundColor", 0);
19
+	}
20
+}

+ 30
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/live/InverseLiveBool.java View File

@@ -0,0 +1,30 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.live;
7
+
8
+import org.openzen.drawablegui.listeners.ListenerHandle;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public class InverseLiveBool implements LiveBool {
15
+	private final LiveBool source;
16
+	
17
+	public InverseLiveBool(LiveBool source) {
18
+		this.source = source;
19
+	}
20
+
21
+	@Override
22
+	public boolean getValue() {
23
+		return !source.getValue();
24
+	}
25
+
26
+	@Override
27
+	public ListenerHandle<Listener> addListener(Listener listener) {
28
+		return source.addListener((oldValue, newValue) -> listener.onChanged(!oldValue, !newValue));
29
+	}
30
+}

+ 2
- 2
DrawableGui/src/main/java/org/openzen/drawablegui/live/LiveConcatList.java View File

@@ -5,8 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui.live;
7 7
 
8
-import java.io.Closeable;
9 8
 import java.util.Iterator;
9
+import org.openzen.drawablegui.Destructible;
10 10
 import org.openzen.drawablegui.listeners.ListenerHandle;
11 11
 import org.openzen.drawablegui.listeners.ListenerList;
12 12
 
@@ -14,7 +14,7 @@ import org.openzen.drawablegui.listeners.ListenerList;
14 14
  *
15 15
  * @author Hoofdgebruiker
16 16
  */
17
-public class LiveConcatList<T> implements Closeable, LiveList<T> {
17
+public class LiveConcatList<T> implements Destructible, LiveList<T> {
18 18
 	private final ListenerList<Listener<T>> listeners = new ListenerList<>();
19 19
 	private final LiveList<T> a;
20 20
 	private final LiveList<T> b;

+ 5
- 2
DrawableGui/src/main/java/org/openzen/drawablegui/live/LiveMappedList.java View File

@@ -5,11 +5,11 @@
5 5
  */
6 6
 package org.openzen.drawablegui.live;
7 7
 
8
-import java.io.Closeable;
9 8
 import java.util.ArrayList;
10 9
 import java.util.Iterator;
11 10
 import java.util.List;
12 11
 import java.util.function.Function;
12
+import org.openzen.drawablegui.Destructible;
13 13
 import org.openzen.drawablegui.listeners.ListenerHandle;
14 14
 import org.openzen.drawablegui.listeners.ListenerList;
15 15
 
@@ -17,7 +17,7 @@ import org.openzen.drawablegui.listeners.ListenerList;
17 17
  *
18 18
  * @author Hoofdgebruiker
19 19
  */
20
-public class LiveMappedList<T, U> implements Closeable, LiveList<U> {
20
+public class LiveMappedList<T, U> implements Destructible, LiveList<U> {
21 21
 	private final ListenerList<Listener<U>> listeners = new ListenerList<>();
22 22
 	private final Function<T, U> projection;
23 23
 	private final List<U> mapped;
@@ -80,6 +80,9 @@ public class LiveMappedList<T, U> implements Closeable, LiveList<U> {
80 80
 		@Override
81 81
 		public void onRemoved(int index, T oldValue) {
82 82
 			U oldMappedValue = mapped.remove(index);
83
+			if (oldMappedValue instanceof AutoCloseable) {
84
+				try { ((AutoCloseable) oldMappedValue).close(); } catch (Exception ex) {}
85
+			}
83 86
 			listeners.accept(listener -> listener.onRemoved(index, oldMappedValue));
84 87
 		}
85 88
 	}

+ 2
- 2
DrawableGui/src/main/java/org/openzen/drawablegui/live/LivePredicateBool.java View File

@@ -5,8 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui.live;
7 7
 
8
-import java.io.Closeable;
9 8
 import java.util.function.Predicate;
9
+import org.openzen.drawablegui.Destructible;
10 10
 import org.openzen.drawablegui.listeners.ListenerHandle;
11 11
 import org.openzen.drawablegui.listeners.ListenerList;
12 12
 
@@ -14,7 +14,7 @@ import org.openzen.drawablegui.listeners.ListenerList;
14 14
  *
15 15
  * @author Hoofdgebruiker
16 16
  */
17
-public class LivePredicateBool<T> implements LiveBool, Closeable, LiveObject.Listener<T> {
17
+public class LivePredicateBool<T> implements LiveBool, Destructible, LiveObject.Listener<T> {
18 18
 	private final ListenerList<LiveBool.Listener> listeners = new ListenerList<>();
19 19
 	private final LiveObject<T> source;
20 20
 	private final Predicate<T> predicate;

+ 8
- 1
DrawableGui/src/main/java/org/openzen/drawablegui/live/SimpleLiveInt.java View File

@@ -14,8 +14,12 @@ import org.openzen.drawablegui.listeners.ListenerList;
14 14
  */
15 15
 public class SimpleLiveInt implements LiveInt {
16 16
 	private final ListenerList<Listener> listeners = new ListenerList<>();
17
-	private int value = 0;
17
+	private int value;
18 18
 
19
+	public SimpleLiveInt(int value) {
20
+		this.value = value;
21
+	}
22
+	
19 23
 	@Override
20 24
 	public int getValue() {
21 25
 		return value;
@@ -23,6 +27,9 @@ public class SimpleLiveInt implements LiveInt {
23 27
 
24 28
 	@Override
25 29
 	public void setValue(int value) {
30
+		if (value == this.value)
31
+			return;
32
+		
26 33
 		int oldValue = this.value;
27 34
 		this.value = value;
28 35
 		listeners.accept(listener -> listener.onChanged(oldValue, value));

+ 3
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/live/SimpleLiveObject.java View File

@@ -27,6 +27,9 @@ public class SimpleLiveObject<T> implements MutableLiveObject<T> {
27 27
 	
28 28
 	@Override
29 29
 	public void setValue(T value) {
30
+		if (value == this.value)
31
+			return;
32
+		
30 33
 		T oldValue = this.value;
31 34
 		this.value = value;
32 35
 		listeners.accept(listener -> listener.onUpdated(oldValue, value));

+ 3
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/live/SimpleLiveString.java View File

@@ -33,6 +33,9 @@ public class SimpleLiveString implements MutableLiveString {
33 33
 
34 34
 	@Override
35 35
 	public void setValue(String value) {
36
+		if (value.equals(this.value))
37
+			return;
38
+		
36 39
 		String oldValue = this.value;
37 40
 		this.value = value;
38 41
 		listeners.accept(listener -> listener.onChanged(oldValue, value));

+ 49
- 24
DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollBar.java View File

@@ -5,15 +5,18 @@
5 5
  */
6 6
 package org.openzen.drawablegui.scroll;
7 7
 
8
-import org.openzen.drawablegui.DCanvas;
9 8
 import org.openzen.drawablegui.DComponent;
10 9
 import org.openzen.drawablegui.DSizing;
11 10
 import org.openzen.drawablegui.DMouseEvent;
12 11
 import org.openzen.drawablegui.DIRectangle;
12
+import org.openzen.drawablegui.DPath;
13
+import org.openzen.drawablegui.DTransform2D;
13 14
 import org.openzen.drawablegui.listeners.ListenerHandle;
14 15
 import org.openzen.drawablegui.live.LiveInt;
15 16
 import org.openzen.drawablegui.live.LiveObject;
16
-import org.openzen.drawablegui.DUIContext;
17
+import org.openzen.drawablegui.draw.DDrawSurface;
18
+import org.openzen.drawablegui.draw.DDrawnRectangle;
19
+import org.openzen.drawablegui.draw.DDrawnShape;
17 20
 import org.openzen.drawablegui.live.MutableLiveObject;
18 21
 import org.openzen.drawablegui.style.DStyleClass;
19 22
 import org.openzen.drawablegui.style.DStylePath;
@@ -32,8 +35,9 @@ public class DScrollBar implements DComponent {
32 35
 	private final ListenerHandle<LiveInt.Listener> targetHeightListener;
33 36
 	private final ListenerHandle<LiveInt.Listener> offsetListener;
34 37
 	
35
-	private DUIContext context;
38
+	private DDrawSurface surface;
36 39
 	private DScrollBarStyle style;
40
+	private int z;
37 41
 	private DIRectangle bounds;
38 42
 	
39 43
 	private int fromY = 0;
@@ -43,6 +47,9 @@ public class DScrollBar implements DComponent {
43 47
 	private int dragStartOffset;
44 48
 	private int dragStartY;
45 49
 	
50
+	private DDrawnRectangle background;
51
+	private DDrawnShape bar;
52
+	
46 53
 	public DScrollBar(DStyleClass styleClass, LiveInt targetHeight, LiveInt offset) {
47 54
 		this.styleClass = styleClass;
48 55
 		this.targetHeight = targetHeight;
@@ -53,10 +60,24 @@ public class DScrollBar implements DComponent {
53 60
 	}
54 61
 
55 62
 	@Override
56
-	public void setContext(DStylePath parent, DUIContext context) {
57
-		this.context = context;
58
-		this.style = new DScrollBarStyle(context.getStylesheets().get(context, parent.getChild("scrollbar", styleClass)));
63
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
64
+		this.surface = surface;
65
+		this.z = z;
66
+		this.style = new DScrollBarStyle(surface.getStylesheet(parent.getChild("scrollbar", styleClass)));
59 67
 		sizing.setValue(new DSizing(style.width, 0));
68
+		
69
+		background = surface.fillRect(z, DIRectangle.EMPTY, style.scrollBarBackgroundColor);
70
+	}
71
+	
72
+	@Override
73
+	public void unmount() {
74
+		background.close();
75
+		background = null;
76
+		
77
+		if (bar != null) {
78
+			bar.close();
79
+			bar = null;
80
+		}
60 81
 	}
61 82
 
62 83
 	@Override
@@ -77,24 +98,9 @@ public class DScrollBar implements DComponent {
77 98
 	@Override
78 99
 	public void setBounds(DIRectangle bounds) {
79 100
 		this.bounds = bounds;
101
+		background.setRectangle(bounds);
80 102
 		recalculate();
81 103
 	}
82
-
83
-	@Override
84
-	public void paint(DCanvas canvas) {
85
-		if (targetHeight.getValue() <= this.bounds.height)
86
-			return; // no scrollbar
87
-		
88
-		canvas.fillRectangle(bounds.x, bounds.y, bounds.width, bounds.height, style.scrollBarBackgroundColor);
89
-		
90
-		int color = style.scrollBarNormalColor;
91
-		if (hovering)
92
-			color = style.scrollBarHoverColor;
93
-		if (dragging)
94
-			color = style.scrollBarPressColor;
95
-		
96
-		canvas.fillRectangle(bounds.x, fromY, this.bounds.width, toY - fromY, color);
97
-	}
98 104
 	
99 105
 	@Override
100 106
 	public void onMouseEnter(DMouseEvent e) {
@@ -139,6 +145,20 @@ public class DScrollBar implements DComponent {
139 145
 	public void close() {
140 146
 		targetHeightListener.close();
141 147
 		offsetListener.close();
148
+		
149
+		unmount();
150
+	}
151
+	
152
+	private void updateBarColor() {
153
+		int color = style.scrollBarNormalColor;
154
+		if (hovering)
155
+			color = style.scrollBarHoverColor;
156
+		if (dragging)
157
+			color = style.scrollBarPressColor;		
158
+		if (targetHeight.getValue() <= this.bounds.height)
159
+			color = 0;
160
+		
161
+		bar.setColor(color);
142 162
 	}
143 163
 	
144 164
 	private void checkHover(DMouseEvent e) {
@@ -150,7 +170,7 @@ public class DScrollBar implements DComponent {
150 170
 			return;
151 171
 		
152 172
 		this.hovering = hovering;
153
-		context.repaint(bounds.x, fromY, bounds.width, toY - fromY);
173
+		updateBarColor();
154 174
 	}
155 175
 	
156 176
 	private void setDragging(boolean dragging) {
@@ -158,7 +178,7 @@ public class DScrollBar implements DComponent {
158 178
 			return;
159 179
 		
160 180
 		this.dragging = dragging;
161
-		context.repaint(bounds.x, fromY, bounds.width, toY - fromY);
181
+		updateBarColor();
162 182
 	}
163 183
 	
164 184
 	private void recalculate() {
@@ -167,6 +187,11 @@ public class DScrollBar implements DComponent {
167 187
 		
168 188
 		fromY = bounds.y + this.bounds.height * offset.getValue() / targetHeight.getValue();
169 189
 		toY = bounds.y + this.bounds.height * (offset.getValue() + this.bounds.height) / targetHeight.getValue();
190
+		
191
+		if (bar != null)
192
+			bar.close();
193
+		bar = surface.fillPath(z + 1, DPath.rectangle(bounds.x, fromY, bounds.width, toY - fromY), DTransform2D.IDENTITY, style.scrollBarNormalColor);
194
+		updateBarColor();
170 195
 	}
171 196
 	
172 197
 	private class ScrollListener implements LiveInt.Listener {

+ 56
- 127
DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollPane.java View File

@@ -6,7 +6,6 @@
6 6
 package org.openzen.drawablegui.scroll;
7 7
 
8 8
 import org.openzen.drawablegui.DAnchor;
9
-import org.openzen.drawablegui.DCanvas;
10 9
 import org.openzen.drawablegui.DClipboard;
11 10
 import org.openzen.drawablegui.DComponent;
12 11
 import org.openzen.drawablegui.DSizing;
@@ -15,14 +14,16 @@ import org.openzen.drawablegui.DFontMetrics;
15 14
 import org.openzen.drawablegui.DIRectangle;
16 15
 import org.openzen.drawablegui.DMouseEvent;
17 16
 import org.openzen.drawablegui.DTimerHandle;
18
-import org.openzen.drawablegui.DTooltip;
19
-import org.openzen.drawablegui.DTooltipHandle;
17
+import org.openzen.drawablegui.DTransform2D;
20 18
 import org.openzen.drawablegui.listeners.ListenerHandle;
21 19
 import org.openzen.drawablegui.live.LiveInt;
22 20
 import org.openzen.drawablegui.live.LiveObject;
23 21
 import org.openzen.drawablegui.live.SimpleLiveInt;
24 22
 import org.openzen.drawablegui.DUIContext;
25 23
 import org.openzen.drawablegui.DUIWindow;
24
+import org.openzen.drawablegui.draw.DDrawSurface;
25
+import org.openzen.drawablegui.draw.DDrawnShape;
26
+import org.openzen.drawablegui.draw.DSubSurface;
26 27
 import org.openzen.drawablegui.style.DStyleClass;
27 28
 import org.openzen.drawablegui.style.DStylePath;
28 29
 import org.openzen.drawablegui.style.DStyleSheets;
@@ -35,27 +36,35 @@ public class DScrollPane implements DComponent {
35 36
 	private final DStyleClass styleClass;
36 37
 	private final DComponent contents;
37 38
 	private final DScrollBar scrollBar;
38
-	private DUIContext context;
39
+	private DDrawSurface surface;
39 40
 	private DIRectangle bounds;
40 41
 	
41 42
 	private DScrollPaneStyle style;
43
+	private int z;
44
+	private DDrawnShape shape;
42 45
 	private final LiveInt contentsHeight;
43 46
 	private final LiveInt offsetX;
44 47
 	private final LiveInt offsetY;
45 48
 	
49
+	private final LiveObject<DSizing> sizing;
50
+	
46 51
 	private final ListenerHandle<LiveInt.Listener> contentsHeightListener;
47 52
 	private final ListenerHandle<LiveInt.Listener> offsetXListener;
48 53
 	private final ListenerHandle<LiveInt.Listener> offsetYListener;
54
+	private final ListenerHandle<LiveObject.Listener<DSizing>> contentsSizingListener;
49 55
 	
50 56
 	private DComponent hovering = null;
51 57
 	
52
-	public DScrollPane(DStyleClass styleClass, DComponent contents) {
58
+	private DSubSurface subSurface;
59
+	
60
+	public DScrollPane(DStyleClass styleClass, DComponent contents, LiveObject<DSizing> sizing) {
61
+		this.sizing = sizing;
53 62
 		this.styleClass = styleClass;
54 63
 		this.contents = contents;
55 64
 		
56
-		contentsHeight = new SimpleLiveInt();
57
-		offsetX = new SimpleLiveInt();
58
-		offsetY = new SimpleLiveInt();
65
+		contentsHeight = new SimpleLiveInt(0);
66
+		offsetX = new SimpleLiveInt(0);
67
+		offsetY = new SimpleLiveInt(0);
59 68
 		
60 69
 		scrollBar = new DScrollBar(DStyleClass.EMPTY, contentsHeight, offsetY);
61 70
 		
@@ -63,7 +72,7 @@ public class DScrollPane implements DComponent {
63 72
 		offsetXListener = offsetX.addListener(new ScrollListener());
64 73
 		offsetYListener = offsetY.addListener(new ScrollListener());
65 74
 		
66
-		contents.getSizing().addListener((oldPreferences, newPreferences) -> {
75
+		contentsSizingListener = contents.getSizing().addListener((oldPreferences, newPreferences) -> {
67 76
 			if (bounds == null)
68 77
 				return;
69 78
 			
@@ -83,21 +92,28 @@ public class DScrollPane implements DComponent {
83 92
 	}
84 93
 
85 94
 	@Override
86
-	public void setContext(DStylePath parent, DUIContext context) {
87
-		this.context = context;
95
+	public void mount(DStylePath parent, int z, DDrawSurface surface) {
96
+		this.surface = surface;
97
+		this.z = z;
88 98
 		
89 99
 		DStylePath path = parent.getChild("scrollpane", styleClass);
90
-		contents.setContext(path, new TranslatedContext());
91
-		scrollBar.setContext(path, context);
92
-		style = new DScrollPaneStyle(context.getStylesheets().get(context, path));
100
+		subSurface = surface.createSubSurface(z + 1);
101
+		contents.mount(path, 1, subSurface);
102
+		scrollBar.mount(path, z + 2, surface);
103
+		style = new DScrollPaneStyle(surface.getStylesheet(path));
104
+	}
105
+	
106
+	@Override
107
+	public void unmount() {
108
+		subSurface.close();
93 109
 		
94
-		if (bounds != null)
95
-			setBounds(bounds);
110
+		contents.unmount();
111
+		scrollBar.unmount();
96 112
 	}
97 113
 
98 114
 	@Override
99 115
 	public LiveObject<DSizing> getSizing() {
100
-		return contents.getSizing(); // TODO: derived preferences
116
+		return sizing;
101 117
 	}
102 118
 
103 119
 	@Override
@@ -114,38 +130,29 @@ public class DScrollPane implements DComponent {
114 130
 	public void setBounds(DIRectangle bounds) {
115 131
 		this.bounds = bounds;
116 132
 		
117
-		if (this.context == null)
118
-			return;
133
+		if (shape != null)
134
+			shape.close();
135
+		shape = surface.shadowPath(z, style.shape.instance(style.margin.apply(bounds)), DTransform2D.IDENTITY, style.backgroundColor, style.shadow);
136
+		style.border.update(surface, z + 1, style.margin.apply(bounds));
119 137
 		
120
-		int height = Math.max(bounds.height - style.border.getPaddingTop() - style.border.getPaddingBottom(),
138
+		int height = Math.max(
139
+				bounds.height - style.border.getPaddingHorizontal(),
121 140
 				contents.getSizing().getValue().preferredHeight);
122 141
 		int scrollBarWidth = scrollBar.getSizing().getValue().preferredWidth;
123 142
 		scrollBar.setBounds(new DIRectangle(
124
-				bounds.x + bounds.width - scrollBarWidth - style.border.getPaddingRight(),
125
-				bounds.y + style.border.getPaddingTop(),
143
+				bounds.x + bounds.width - scrollBarWidth - style.border.getPaddingRight() - style.margin.right,
144
+				bounds.y + style.border.getPaddingTop() + style.margin.top,
126 145
 				scrollBarWidth,
127
-				bounds.height - style.border.getPaddingTop() - style.border.getPaddingBottom()));
146
+				bounds.height - style.border.getPaddingVertical() - style.margin.getVertical()));
128 147
 		contents.setBounds(new DIRectangle(0, 0, bounds.width - scrollBar.getBounds().width, height));
129 148
 		contentsHeight.setValue(height);
130
-	}
131
-
132
-	@Override
133
-	public void paint(DCanvas canvas) {
134
-		if (bounds == null)
135
-			return;
136 149
 		
137
-		style.border.paint(canvas, bounds);
138
-		scrollBar.paint(canvas);
139
-		
140
-		canvas.pushBounds(new DIRectangle(
141
-				bounds.x + style.border.getPaddingLeft(),
142
-				bounds.y + style.border.getPaddingTop(),
143
-				bounds.width - style.border.getPaddingLeft() - style.border.getPaddingTop() - scrollBar.getBounds().width,
144
-				bounds.height - style.border.getPaddingTop() - style.border.getPaddingBottom()));
145
-		canvas.pushOffset(bounds.x - offsetX.getValue(), bounds.y - offsetY.getValue());
146
-		contents.paint(canvas);
147
-		canvas.popOffset();
148
-		canvas.popBounds();
150
+		subSurface.setOffset(bounds.x - offsetX.getValue(), bounds.y - offsetY.getValue());
151
+		subSurface.setClip(new DIRectangle(
152
+				bounds.x + style.margin.left + style.border.getPaddingLeft(),
153
+				bounds.y + style.margin.top + style.border.getPaddingTop(),
154
+				bounds.width - style.margin.getHorizontal() - style.border.getPaddingHorizontal(),
155
+				bounds.height - style.margin.getVertical() - style.border.getPaddingVertical()));
149 156
 	}
150 157
 	
151 158
 	@Override
@@ -213,6 +220,12 @@ public class DScrollPane implements DComponent {
213 220
 	@Override
214 221
 	public void close() {
215 222
 		contents.close();
223
+		unmount();
224
+		
225
+		contentsSizingListener.close();
226
+		contentsHeightListener.close();
227
+		offsetXListener.close();
228
+		offsetYListener.close();
216 229
 	}
217 230
 	
218 231
 	private DMouseEvent forward(DComponent target, DMouseEvent e) {
@@ -256,90 +269,6 @@ public class DScrollPane implements DComponent {
256 269
 		return y - bounds.y + offsetY.getValue();
257 270
 	}
258 271
 	
259
-	private class TranslatedContext implements DUIContext {
260
-		
261
-		@Override
262
-		public DStyleSheets getStylesheets(){
263
-			return context.getStylesheets();
264
-		}
265
-
266
-		@Override
267
-		public float getScale() {
268
-			return context.getScale();
269
-		}
270
-		
271
-		@Override
272
-		public float getTextScale() {
273
-			return context.getTextScale();
274
-		}
275
-
276
-		@Override
277
-		public void repaint(int x, int y, int width, int height) {
278
-			int left = toGlobalX(x);
279
-			int top = toGlobalY(y);
280
-			int right = left + width;
281
-			int bottom = top + height;
282
-			
283
-			left = Math.max(bounds.x, left);
284
-			top = Math.max(bounds.y, top);
285
-			right = Math.min(bounds.x + bounds.width, right);
286
-			bottom = Math.min(bounds.y + bounds.height, bottom);
287
-			
288
-			if (left >= right || top >= bottom)
289
-				return;
290
-			
291
-			context.repaint(left, top, right - left, bottom - top);
292
-		}
293
-
294
-		@Override
295
-		public void setCursor(Cursor cursor) {
296
-			context.setCursor(cursor);
297
-		}
298
-
299
-		@Override
300
-		public DFontMetrics getFontMetrics(DFont font) {
301
-			return context.getFontMetrics(font);
302
-		}
303
-
304
-		@Override
305
-		public void scrollInView(int x, int y, int width, int height) {
306
-			if (y < offsetY.getValue())
307
-				offsetY.setValue(y);
308
-			if (y + height > offsetY.getValue() + bounds.height)
309
-				offsetY.setValue(y + height - bounds.height);
310
-		}
311
-
312
-		@Override
313
-		public DTimerHandle setTimer(int millis, Runnable target) {
314
-			return context.setTimer(millis, target);
315
-		}
316
-
317
-		@Override
318
-		public DClipboard getClipboard() {
319
-			return context.getClipboard();
320
-		}
321
-
322
-		@Override
323
-		public DUIWindow getWindow() {
324
-			return context.getWindow();
325
-		}
326
-
327
-		@Override
328
-		public DUIWindow openDialog(int x, int y, DAnchor anchor, String title, DComponent root) {
329
-			return context.openDialog(toGlobalX(x), toGlobalY(y), anchor, title, root);
330
-		}
331
-
332
-		@Override
333
-		public DUIWindow openView(int x, int y, DAnchor anchor, DComponent root) {
334
-			return context.openView(toGlobalX(x), toGlobalY(y), anchor, root);
335
-		}
336
-		
337
-		@Override
338
-		public DTooltipHandle openTooltip(int x, int y, DTooltip tooltip) {
339
-			return context.openTooltip(toGlobalX(x), toGlobalY(y), tooltip);
340
-		}
341
-	}
342
-	
343 272
 	private class ScrollListener implements LiveInt.Listener {
344 273
 
345 274
 		@Override
@@ -352,8 +281,8 @@ public class DScrollPane implements DComponent {
352 281
 			
353 282
 			if (value != offsetY.getValue())
354 283
 				offsetY.setValue(value);
355
-			if (context != null && bounds != null)
356
-				context.repaint(bounds);
284
+			
285
+			subSurface.setOffset(bounds.x - offsetX.getValue(), bounds.y - offsetY.getValue());
357 286
 		}
358 287
 	}
359 288
 }

+ 3
- 6
DrawableGui/src/main/java/org/openzen/drawablegui/scroll/DScrollPaneStyle.java View File

@@ -5,18 +5,15 @@
5 5
  */
6 6
 package org.openzen.drawablegui.scroll;
7 7
 
8
-import org.openzen.drawablegui.border.DBorder;
9
-import org.openzen.drawablegui.border.DLineBorder;
8
+import org.openzen.drawablegui.style.DBaseStyle;
10 9
 import org.openzen.drawablegui.style.DStyleDefinition;
11 10
 
12 11
 /**
13 12
  *
14 13
  * @author Hoofdgebruiker
15 14
  */
16
-public class DScrollPaneStyle {
17
-	public final DBorder border;
18
-	
15
+public class DScrollPaneStyle extends DBaseStyle {
19 16
 	public DScrollPaneStyle(DStyleDefinition style) {
20
-		this.border = style.getBorder("border", context -> new DLineBorder(0xFF888888, 1));
17
+		super(style);
21 18
 	}
22 19
 }

+ 45
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DBaseStyle.java View File

@@ -0,0 +1,45 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.border.DBorder;
9
+import org.openzen.drawablegui.border.DEmptyBorder;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public class DBaseStyle {
16
+	public final DMargin margin;
17
+	public final DBorder border;
18
+	public final DShadow shadow;
19
+	public final DShape shape;
20
+	public final int backgroundColor;
21
+	
22
+	public DBaseStyle(DStyleDefinition style) {
23
+		border = style.getBorder("border", DEmptyBorder.ELEMENT);
24
+		backgroundColor = style.getColor("backgroundColor", 0);
25
+		margin = style.getMargin("margin", DMargin.EMPTY_ELEMENT);
26
+		shape = style.getShape("shape", DRectangleShape.ELEMENT);
27
+		shadow = style.getShadow("shadow", DShadow.NONE_ELEMENT);
28
+	}
29
+	
30
+	public DBaseStyle(DStyleDefinition style, DBorderElement defaultBorder, int defaultBackgroundColor) {
31
+		border = style.getBorder("border", defaultBorder);
32
+		backgroundColor = style.getColor("backgroundColor", defaultBackgroundColor);
33
+		margin = style.getMargin("margin", DMargin.EMPTY_ELEMENT);
34
+		shape = style.getShape("shape", DRectangleShape.ELEMENT);
35
+		shadow = style.getShadow("shadow", DShadow.NONE_ELEMENT);
36
+	}
37
+	
38
+	public DBaseStyle(DStyleDefinition style, DBorderElement defaultBorder, int defaultBackgroundColor, DShapeElement defaultShape, DShadowElement defaultShadow) {
39
+		border = style.getBorder("border", defaultBorder);
40
+		backgroundColor = style.getColor("backgroundColor", defaultBackgroundColor);
41
+		margin = style.getMargin("margin", DMargin.EMPTY_ELEMENT);
42
+		shape = style.getShape("shape", defaultShape);
43
+		shadow = style.getShadow("shadow", defaultShadow);
44
+	}
45
+}

+ 22
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DBorderElement.java View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+import org.openzen.drawablegui.border.DBorder;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public interface DBorderElement extends DStyleElement {
16
+	DBorder eval(DUIContext context);
17
+	
18
+	@Override
19
+	default DBorderElement asBorder() {
20
+		return this;
21
+	}
22
+}

+ 23
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DColorElement.java View File

@@ -0,0 +1,23 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+/**
9
+ *
10
+ * @author Hoofdgebruiker
11
+ */
12
+public class DColorElement implements DStyleElement {
13
+	private final int color;
14
+	
15
+	public DColorElement(int color) {
16
+		this.color = color;
17
+	}
18
+	
19
+	@Override
20
+	public int asColor() {
21
+		return color;
22
+	}
23
+}

+ 6
- 1
DrawableGui/src/main/java/org/openzen/drawablegui/style/DDimension.java View File

@@ -11,10 +11,15 @@ import org.openzen.drawablegui.DUIContext;
11 11
  *
12 12
  * @author Hoofdgebruiker
13 13
  */
14
-public interface DDimension {
14
+public interface DDimension extends DStyleElement {
15 15
 	float eval(DUIContext context);
16 16
 	
17 17
 	default int evalInt(DUIContext context) {
18 18
 		return (int)(eval(context) + 0.5f);
19 19
 	}
20
+	
21
+	@Override
22
+	default DDimension asDimension() {
23
+		return this;
24
+	}
20 25
 }

+ 16
- 7
DrawableGui/src/main/java/org/openzen/drawablegui/style/DEmptyStyleDefinition.java View File

@@ -5,7 +5,6 @@
5 5
  */
6 6
 package org.openzen.drawablegui.style;
7 7
 
8
-import java.util.function.Function;
9 8
 import org.openzen.drawablegui.DFont;
10 9
 import org.openzen.drawablegui.DUIContext;
11 10
 import org.openzen.drawablegui.border.DBorder;
@@ -37,17 +36,27 @@ public class DEmptyStyleDefinition implements DStyleDefinition {
37 36
 	}
38 37
 
39 38
 	@Override
40
-	public DShadow getShadow(String name, Function<DUIContext, DShadow> defaultValue) {
41
-		return defaultValue.apply(context);
39
+	public DShadow getShadow(String name, DShadowElement defaultValue) {
40
+		return defaultValue.eval(context);
42 41
 	}
43 42
 
44 43
 	@Override
45
-	public DFont getFont(String name, Function<DUIContext, DFont> defaultValue) {
46
-		return defaultValue.apply(context);
44
+	public DFont getFont(String name, DFontElement defaultValue) {
45
+		return defaultValue.eval(context);
47 46
 	}
48 47
 
49 48
 	@Override
50
-	public DBorder getBorder(String name, Function<DUIContext, DBorder> defaultValue) {
51
-		return defaultValue.apply(context);
49
+	public DBorder getBorder(String name, DBorderElement defaultValue) {
50
+		return defaultValue.eval(context);
51
+	}
52
+	
53
+	@Override
54
+	public DMargin getMargin(String name, DMarginElement defaultValue) {
55
+		return defaultValue.eval(context);
56
+	}
57
+	
58
+	@Override
59
+	public DShape getShape(String name, DShapeElement defaultValue) {
60
+		return defaultValue.eval(context);
52 61
 	}
53 62
 }

+ 23
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DEmptyStylesheet.java View File

@@ -0,0 +1,23 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public class DEmptyStylesheet implements DStylesheet {
15
+	public static final DEmptyStylesheet INSTANCE = new DEmptyStylesheet();
16
+	
17
+	private DEmptyStylesheet() {}
18
+
19
+	@Override
20
+	public DStyleDefinition getInstance(DUIContext context) {
21
+		return new DEmptyStyleDefinition(context);
22
+	}
23
+}

+ 1
- 1
DrawableGui/src/main/java/org/openzen/drawablegui/style/DEmptyStylesheets.java View File

@@ -16,6 +16,6 @@ public class DEmptyStylesheets implements DStyleSheets {
16 16
 
17 17
 	@Override
18 18
 	public DStyleDefinition get(DUIContext context, DStylePath path) {
19
-		return new DEmptyStyleDefinition(context);
19
+		return path.getInline(context);
20 20
 	}
21 21
 }

+ 23
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DFontElement.java View File

@@ -0,0 +1,23 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DFont;
9
+import org.openzen.drawablegui.DUIContext;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+@FunctionalInterface
16
+public interface DFontElement extends DStyleElement {
17
+	DFont eval(DUIContext context);
18
+	
19
+	@Override
20
+	default DFontElement asFont() {
21
+		return this;
22
+	}
23
+}

+ 49
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DMargin.java View File

@@ -0,0 +1,49 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public class DMargin {
15
+	public static final DMargin EMPTY = new DMargin(0);
16
+	public static final DMarginElement EMPTY_ELEMENT = context -> EMPTY;
17
+	
18
+	public final int left;
19
+	public final int right;
20
+	public final int top;
21
+	public final int bottom;
22
+	
23
+	public DMargin(int left, int right, int top, int bottom) {
24
+		this.left = left;
25
+		this.right = right;
26
+		this.top = top;
27
+		this.bottom = bottom;
28
+	}
29
+	
30
+	public DMargin(int amount) {
31
+		this(amount, amount, amount, amount);
32
+	}
33
+	
34
+	public int getVertical() {
35
+		return top + bottom;
36
+	}
37
+	
38
+	public int getHorizontal() {
39
+		return left + right;
40
+	}
41
+	
42
+	public DIRectangle apply(DIRectangle bounds) {
43
+		return new DIRectangle(
44
+				bounds.x + left,
45
+				bounds.y + top,
46
+				bounds.width - left - right,
47
+				bounds.height - top - bottom);
48
+	}
49
+}

+ 20
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DMarginElement.java View File

@@ -0,0 +1,20 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public interface DMarginElement extends DStyleElement {
15
+	DMargin eval(DUIContext context);
16
+	
17
+	default DMarginElement asMargin() {
18
+		return this;
19
+	}
20
+}

+ 2
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DPxDimension.java View File

@@ -12,6 +12,8 @@ import org.openzen.drawablegui.DUIContext;
12 12
  * @author Hoofdgebruiker
13 13
  */
14 14
 public class DPxDimension implements DDimension {
15
+	public static final DPxDimension ZERO = new DPxDimension(0);
16
+	
15 17
 	private final float pixels;
16 18
 	
17 19
 	public DPxDimension(float pixels) {

+ 23
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DRectangleShape.java View File

@@ -0,0 +1,23 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.DPath;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public class DRectangleShape implements DShape {
16
+	public static final DRectangleShape INSTANCE = new DRectangleShape();
17
+	public static final DShapeElement ELEMENT = context -> INSTANCE;
18
+
19
+	@Override
20
+	public DPath instance(DIRectangle bounds) {
21
+		return DPath.rectangle(bounds.x, bounds.y, bounds.width, bounds.height);
22
+	}
23
+}

+ 36
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DRoundedRectangleShape.java View File

@@ -0,0 +1,36 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.DPath;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public class DRoundedRectangleShape implements DShape {
16
+	private final float radiusTopLeft;
17
+	private final float radiusTopRight;
18
+	private final float radiusBottomLeft;
19
+	private final float radiusBottomRight;
20
+	
21
+	public DRoundedRectangleShape(float radius) {
22
+		this(radius, radius, radius, radius);
23
+	}
24
+	
25
+	public DRoundedRectangleShape(float radiusTopLeft, float radiusTopRight, float radiusBottomLeft, float radiusBottomRight) {
26
+		this.radiusTopLeft = radiusTopLeft;
27
+		this.radiusTopRight = radiusTopRight;
28
+		this.radiusBottomLeft = radiusBottomLeft;
29
+		this.radiusBottomRight = radiusBottomRight;
30
+	}
31
+
32
+	@Override
33
+	public DPath instance(DIRectangle bounds) {
34
+		return DPath.roundedRectangle(bounds.x, bounds.y, bounds.width, bounds.height, radiusTopLeft, radiusTopRight, radiusBottomLeft, radiusBottomRight);
35
+	}
36
+}

+ 1
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DShadow.java View File

@@ -11,6 +11,7 @@ package org.openzen.drawablegui.style;
11 11
  */
12 12
 public class DShadow {
13 13
 	public static final DShadow NONE = new DShadow(0, 0, 0, 0);
14
+	public static final DShadowElement NONE_ELEMENT = context -> NONE;
14 15
 	
15 16
 	public final int color;
16 17
 	public final float offsetX;

+ 21
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DShadowElement.java View File

@@ -0,0 +1,21 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public interface DShadowElement extends DStyleElement {
15
+	DShadow eval(DUIContext context);
16
+	
17
+	@Override
18
+	default DShadowElement asShadow() {
19
+		return this;
20
+	}
21
+}

+ 17
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DShape.java View File

@@ -0,0 +1,17 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DIRectangle;
9
+import org.openzen.drawablegui.DPath;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public interface DShape {
16
+	DPath instance(DIRectangle bounds);
17
+}

+ 22
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DShapeElement.java View File

@@ -0,0 +1,22 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+@FunctionalInterface
15
+public interface DShapeElement extends DStyleElement {
16
+	DShape eval(DUIContext context);
17
+	
18
+	@Override
19
+	default DShapeElement asShape() {
20
+		return this;
21
+	}
22
+}

+ 100
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DSimpleStylesheet.java View File

@@ -0,0 +1,100 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import java.util.Map;
9
+import org.openzen.drawablegui.DFont;
10
+import org.openzen.drawablegui.DUIContext;
11
+import org.openzen.drawablegui.border.DBorder;
12
+
13
+/**
14
+ *
15
+ * @author Hoofdgebruiker
16
+ */
17
+public class DSimpleStylesheet implements DStylesheet {
18
+	private final Map<String, DStyleElement> elements;
19
+	
20
+	public DSimpleStylesheet(Map<String, DStyleElement> elements) {
21
+		this.elements = elements;
22
+	}
23
+
24
+	@Override
25
+	public DStyleDefinition getInstance(DUIContext context) {
26
+		return new Instance(context);
27
+	}
28
+	
29
+	private class Instance implements DStyleDefinition {
30
+		private final DUIContext context;
31
+		
32
+		private Instance(DUIContext context) {
33
+			this.context = context;
34
+		}
35
+
36
+		@Override
37
+		public int getDimension(String name, DDimension defaultValue) {
38
+			if (!elements.containsKey(name))
39
+				return defaultValue.evalInt(context);
40
+			
41
+			return elements.get(name).asDimension().evalInt(context);
42
+		}
43
+
44
+		@Override
45
+		public float getFloatDimension(String name, DDimension defaultValue) {
46
+			if (!elements.containsKey(name))
47
+				return defaultValue.eval(context);
48
+			
49
+			return elements.get(name).asDimension().eval(context);
50
+		}
51
+
52
+		@Override
53
+		public int getColor(String name, int defaultValue) {
54
+			if (!elements.containsKey(name))
55
+				return defaultValue;
56
+			
57
+			return elements.get(name).asColor();
58
+		}
59
+
60
+		@Override
61
+		public DShadow getShadow(String name, DShadowElement defaultValue) {
62
+			if (!elements.containsKey(name))
63
+				return defaultValue.eval(context);
64
+			
65
+			return elements.get(name).asShadow().eval(context);
66
+		}
67
+
68
+		@Override
69
+		public DFont getFont(String name, DFontElement defaultValue) {
70
+			if (!elements.containsKey(name))
71
+				return defaultValue.eval(context);
72
+			
73
+			return elements.get(name).asFont().eval(context);
74
+		}
75
+
76
+		@Override
77
+		public DBorder getBorder(String name, DBorderElement defaultValue) {
78
+			if (!elements.containsKey(name))
79
+				return defaultValue.eval(context);
80
+			
81
+			return elements.get(name).asBorder().eval(context);
82
+		}
83
+		
84
+		@Override
85
+		public DMargin getMargin(String name, DMarginElement defaultValue) {
86
+			if (!elements.containsKey(name))
87
+				return defaultValue.eval(context);
88
+			
89
+			return elements.get(name).asMargin().eval(context);
90
+		}
91
+		
92
+		@Override
93
+		public DShape getShape(String name, DShapeElement defaultValue) {
94
+			if (!elements.containsKey(name))
95
+				return defaultValue.eval(context);
96
+			
97
+			return elements.get(name).asShape().eval(context);
98
+		}
99
+	}
100
+}

+ 13
- 3
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStyleClass.java View File

@@ -11,17 +11,27 @@ package org.openzen.drawablegui.style;
11 11
  */
12 12
 public class DStyleClass {
13 13
 	private static final String[] NO_CLASSES = new String[0];
14
-	public static final DStyleClass EMPTY = new DStyleClass(null, NO_CLASSES);
14
+	public static final DStyleClass EMPTY = new DStyleClass(null, NO_CLASSES, DEmptyStylesheet.INSTANCE);
15 15
 	
16 16
 	public static DStyleClass forId(String id) {
17
-		return new DStyleClass(id, NO_CLASSES);
17
+		return new DStyleClass(id, NO_CLASSES, DEmptyStylesheet.INSTANCE);
18
+	}
19
+	
20
+	public static DStyleClass inline(DStylesheet stylesheet) {
21
+		return new DStyleClass(null, NO_CLASSES, stylesheet);
22
+	}
23
+	
24
+	public static DStyleClass inline(String id, DStylesheet stylesheet) {
25
+		return new DStyleClass(id, NO_CLASSES, stylesheet);
18 26
 	}
19 27
 	
20 28
 	public final String id;
21 29
 	public final String[] classes;
30
+	public final DStylesheet inline;
22 31
 	
23
-	public DStyleClass(String id, String[] classes) {
32
+	public DStyleClass(String id, String[] classes, DStylesheet inline) {
24 33
 		this.id = id;
25 34
 		this.classes = classes;
35
+		this.inline = inline;
26 36
 	}
27 37
 }

+ 7
- 5
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStyleDefinition.java View File

@@ -5,9 +5,7 @@
5 5
  */
6 6
 package org.openzen.drawablegui.style;
7 7
 
8
-import java.util.function.Function;
9 8
 import org.openzen.drawablegui.DFont;
10
-import org.openzen.drawablegui.DUIContext;
11 9
 import org.openzen.drawablegui.border.DBorder;
12 10
 
13 11
 /**
@@ -21,9 +19,13 @@ public interface DStyleDefinition {
21 19
 	
22 20
 	public int getColor(String name, int defaultValue);
23 21
 	
24
-	public DShadow getShadow(String name, Function<DUIContext, DShadow> defaultValue);
22
+	public DShadow getShadow(String name, DShadowElement defaultValue);
25 23
 	
26
-	public DFont getFont(String name, Function<DUIContext, DFont> defaultValue);
24
+	public DFont getFont(String name, DFontElement defaultValue);
27 25
 	
28
-	public DBorder getBorder(String name, Function<DUIContext, DBorder> defaultValue);
26
+	public DBorder getBorder(String name, DBorderElement defaultValue);
27
+	
28
+	public DMargin getMargin(String name, DMarginElement defaultValue);
29
+	
30
+	public DShape getShape(String name, DShapeElement defaultValue);
29 31
 }

+ 45
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStyleElement.java View File

@@ -0,0 +1,45 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import java.util.function.Function;
9
+import org.openzen.drawablegui.DFont;
10
+import org.openzen.drawablegui.DUIContext;
11
+import org.openzen.drawablegui.border.DBorder;
12
+
13
+/**
14
+ *
15
+ * @author Hoofdgebruiker
16
+ */
17
+public interface DStyleElement {
18
+	default DDimension asDimension() {
19
+		throw new RuntimeException("Not a dimension!");
20
+	}
21
+	
22
+	default int asColor() {
23
+		throw new RuntimeException("Not a color!");
24
+	}
25
+	
26
+	default DFontElement asFont() {
27
+		throw new RuntimeException("Not a font!");
28
+	}
29
+	
30
+	default DBorderElement asBorder() {
31
+		throw new RuntimeException("Not a border!");
32
+	}
33
+	
34
+	default DMarginElement asMargin() {
35
+		throw new RuntimeException("Not a margin!");
36
+	}
37
+	
38
+	default DShadowElement asShadow() {
39
+		throw new RuntimeException("Not a shadow!");
40
+	}
41
+	
42
+	default DShapeElement asShape() {
43
+		throw new RuntimeException("Not a shape!");
44
+	}
45
+}

+ 4
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylePath.java View File

@@ -5,10 +5,14 @@
5 5
  */
6 6
 package org.openzen.drawablegui.style;
7 7
 
8
+import org.openzen.drawablegui.DUIContext;
9
+
8 10
 /**
9 11
  *
10 12
  * @author Hoofdgebruiker
11 13
  */
12 14
 public interface DStylePath {
13 15
 	public DStylePath getChild(String element, DStyleClass styleClass);
16
+	
17
+	public DStyleDefinition getInline(DUIContext context);
14 18
 }

+ 12
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylePathRoot.java View File

@@ -5,6 +5,8 @@
5 5
  */
6 6
 package org.openzen.drawablegui.style;
7 7
 
8
+import org.openzen.drawablegui.DUIContext;
9
+
8 10
 /**
9 11
  *
10 12
  * @author Hoofdgebruiker
@@ -19,6 +21,11 @@ public class DStylePathRoot implements DStylePath {
19 21
 		return new DStyleChildElement(this, element, styleClass);
20 22
 	}
21 23
 	
24
+	@Override
25
+	public DStyleDefinition getInline(DUIContext context) {
26
+		return new DEmptyStyleDefinition(context);
27
+	}
28
+	
22 29
 	private static class DStyleChildElement implements DStylePath {
23 30
 		private final DStylePath parent;
24 31
 		private final String element;
@@ -34,5 +41,10 @@ public class DStylePathRoot implements DStylePath {
34 41
 		public DStylePath getChild(String element, DStyleClass styleClass) {
35 42
 			return new DStyleChildElement(this, element, styleClass);
36 43
 		}
44
+
45
+		@Override
46
+		public DStyleDefinition getInline(DUIContext context) {
47
+			return styleClass.inline.getInstance(context);
48
+		}
37 49
 	}
38 50
 }

+ 16
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylesheet.java View File

@@ -0,0 +1,16 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import org.openzen.drawablegui.DUIContext;
9
+
10
+/**
11
+ *
12
+ * @author Hoofdgebruiker
13
+ */
14
+public interface DStylesheet {
15
+	DStyleDefinition getInstance(DUIContext context);
16
+}

+ 66
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/style/DStylesheetBuilder.java View File

@@ -0,0 +1,66 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.style;
7
+
8
+import java.util.HashMap;
9
+import java.util.Map;
10
+
11
+/**
12
+ *
13
+ * @author Hoofdgebruiker
14
+ */
15
+public class DStylesheetBuilder {
16
+	private final Map<String, DStyleElement> elements = new HashMap<>();
17
+	
18
+	public DStylesheetBuilder dimensionDp(String name, float value) {
19
+		elements.put(name, new DDpDimension(value));
20
+		return this;
21
+	}
22
+	
23
+	public DStylesheetBuilder dimensionPx(String name, float value) {
24
+		elements.put(name, new DPxDimension(value));
25
+		return this;
26
+	}
27
+	
28
+	public DStylesheetBuilder dimensionSp(String name, float value) {
29
+		elements.put(name, new DSpDimension(value));
30
+		return this;
31
+	}
32
+	
33
+	public DStylesheetBuilder color(String name, int value) {
34
+		elements.put(name, new DColorElement(value));
35
+		return this;
36
+	}
37
+	
38
+	public DStylesheetBuilder font(String name, DFontElement font) {
39
+		elements.put(name, font);
40
+		return this;
41
+	}
42
+	
43
+	public DStylesheetBuilder shadow(String name, DShadowElement shadow) {
44
+		elements.put(name, shadow);
45
+		return this;
46
+	}
47
+	
48
+	public DStylesheetBuilder border(String name, DBorderElement border) {
49
+		elements.put(name, border);
50
+		return this;
51
+	}
52
+	
53
+	public DStylesheetBuilder marginDp(String name, float value) {
54
+		elements.put(name, (DMarginElement)context -> new DMargin(context.dp(value)));
55
+		return this;
56
+	}
57
+	
58
+	public DStylesheetBuilder shape(String name, DShapeElement shape) {
59
+		elements.put(name, shape);
60
+		return this;
61
+	}
62
+	
63
+	public DStylesheet build() {
64
+		return new DSimpleStylesheet(elements);
65
+	}
66
+}

+ 0
- 209
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingCanvas.java View File

@@ -1,209 +0,0 @@
1
-/*
2
- * To change this license header, choose License Headers in Project Properties.
3
- * To change this template file, choose Tools | Templates
4
- * and open the template in the editor.
5
- */
6
-package org.openzen.drawablegui.swing;
7
-
8
-import java.awt.BasicStroke;
9
-import java.awt.Color;
10
-import java.awt.Font;
11
-import java.awt.Graphics2D;
12
-import java.awt.Rectangle;
13
-import java.awt.RenderingHints;
14
-import java.awt.geom.AffineTransform;
15
-import java.awt.geom.GeneralPath;
16
-import java.awt.image.BufferedImage;
17
-import java.awt.image.ConvolveOp;
18
-import java.awt.image.Kernel;
19
-import java.util.Stack;
20
-import org.openzen.drawablegui.DCanvas;
21
-import org.openzen.drawablegui.DFont;
22
-import org.openzen.drawablegui.DFontFamily;
23
-import org.openzen.drawablegui.DTransform2D;
24
-import org.openzen.drawablegui.DIRectangle;
25
-import org.openzen.drawablegui.DPath;
26
-import org.openzen.drawablegui.DPathBoundsCalculator;
27
-import org.openzen.drawablegui.DUIContext;
28
-import org.openzen.drawablegui.style.DShadow;
29
-
30
-/**
31
- *
32
- * @author Hoofdgebruiker
33
- */
34
-public class SwingCanvas implements DCanvas {
35
-	private final Graphics2D g;
36
-	private final SwingGraphicsContext context;
37
-	private final Stack<Rectangle> bounds = new Stack<>();
38
-	private final Stack<AffineTransform> transformStack = new Stack<>();
39
-	
40
-	public SwingCanvas(Graphics2D g, SwingGraphicsContext context, DIRectangle bounds) {
41
-		this.g = g;
42
-		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
43
-		g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
44
-		
45
-		this.context = context;
46
-		
47
-		if (bounds != null)
48
-			pushBounds(new DIRectangle(bounds.x, bounds.y, bounds.width, bounds.height));
49
-	}
50
-	
51
-	@Override
52
-	public void pushBounds(DIRectangle bounds) {
53
-		this.bounds.push(g.getClipBounds());
54
-		g.setClip(bounds.x, bounds.y, bounds.width, bounds.height);
55
-	}
56
-	
57
-	@Override
58
-	public void popBounds() {
59
-		Rectangle bounds = this.bounds.pop();
60
-		g.setClip(bounds.x, bounds.y, bounds.width, bounds.height);
61
-	}
62
-	
63
-	@Override
64
-	public void pushOffset(int x, int y) {
65
-		transformStack.push(g.getTransform());
66
-		g.transform(AffineTransform.getTranslateInstance(x, y));
67
-	}
68
-	
69
-	@Override
70
-	public void popOffset() {
71
-		g.setTransform(transformStack.pop());
72
-	}
73
-	
74
-	@Override
75
-	public DIRectangle getBounds() {
76
-		Rectangle bounds = g.getClipBounds();
77
-		return new DIRectangle(bounds.x, bounds.y, bounds.width, bounds.height);
78
-	}
79
-
80
-	@Override
81
-	public void drawText(DFont font, int color, float x, float y, String text) {
82
-		prepare(font);
83
-		g.setColor(new Color(color, true));
84
-		g.setFont((Font) font.cached);
85
-		g.drawString(text, x, y);
86
-	}
87
-
88
-	@Override
89
-	public DUIContext getContext() {
90
-		return context;
91
-	}
92
-
93
-	@Override
94
-	public void strokePath(DPath path, DTransform2D transform, int color, float lineWidth) {
95
-		if (color == 0)
96
-			return;
97
-		
98
-		AffineTransform old = g.getTransform();
99
-		GeneralPath jPath = context.getPath(path);
100
-		g.setColor(new Color(color, true));
101
-		g.setStroke(new BasicStroke(lineWidth));
102
-		g.transform(getTransform(transform));
103
-		g.draw(jPath);
104
-		g.setTransform(old);
105
-	}
106
-
107
-	@Override
108
-	public void fillPath(DPath path, DTransform2D transform, int color) {
109
-		if (color == 0)
110
-			return;
111
-		
112
-		AffineTransform old = g.getTransform();
113
-		GeneralPath jPath = context.getPath(path);
114
-		g.setColor(new Color(color, true));
115
-		g.transform(getTransform(transform));
116
-		g.fill(jPath);
117
-		g.setTransform(old);
118
-	}
119
-
120
-	@Override
121
-	public void shadowPath(DPath path, DTransform2D transform, DShadow shadow) {
122
-		if (shadow.color == 0)
123
-			return;
124
-		
125
-		if (shadow.radius == 0) {
126
-			fillPath(path, transform, shadow.color);
127
-			return;
128
-		}
129
-		
130
-		DIRectangle bounds = DPathBoundsCalculator.getBounds(path, transform.offset(shadow.offsetX, shadow.offsetY));
131
-		int offset = 2 * (int)Math.ceil(shadow.radius);
132
-		
133
-		GeneralPath jPath = context.getPath(path);
134
-		
135
-		BufferedImage image = new BufferedImage(bounds.width + 2 * offset, bounds.height + 2 * offset, BufferedImage.TYPE_INT_ARGB_PRE);
136
-		Graphics2D imageG = (Graphics2D) image.getGraphics();
137
-		
138
-		imageG.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
139
-		imageG.setColor(new Color(shadow.color, true));
140
-		imageG.setTransform(getTransform(transform.offset(offset + shadow.offsetX - bounds.x, offset + shadow.offsetY - bounds.y)));
141
-		imageG.fill(jPath);
142
-		
143
-		image = getGaussianBlurFilter((int)Math.ceil(shadow.radius), true).filter(image, null);
144
-		image = getGaussianBlurFilter((int)Math.ceil(shadow.radius), false).filter(image, null);
145
-		g.drawImage(image, bounds.x - offset, bounds.y - offset, null);
146
-	}
147
-
148
-	@Override
149
-	public void fillRectangle(int x, int y, int width, int height, int color) {
150
-		if (color == 0)
151
-			return;
152
-		
153
-		g.setColor(new Color(color, true));
154
-		g.fillRect(x, y, width, height);
155
-	}
156
-	
157
-	public static void prepare(DFont font) {
158
-		if (font.cached != null && font.cached instanceof Font)
159
-			return;
160
-		
161
-		String baseFontName = font.family == DFontFamily.CODE ? "Consolas" : Font.DIALOG;
162
-		int style = 0;
163
-		if (font.bold)
164
-			style |= Font.BOLD;
165
-		if (font.italic)
166
-			style |= Font.ITALIC;
167
-		
168
-		font.cached = Font.decode(baseFontName).deriveFont(style, font.size);
169
-	}
170
-	
171
-	private AffineTransform getTransform(DTransform2D transform) {
172
-		return new AffineTransform(transform.xx, transform.xy, transform.yx, transform.yy, transform.dx, transform.dy);
173
-	}
174
-    
175
-	
176
-	// taken from http://www.java2s.com/Code/Java/Advanced-Graphics/GaussianBlurDemo.htm
177
-    public static ConvolveOp getGaussianBlurFilter(int radius, boolean horizontal) {
178
-        if (radius < 1) {
179
-            throw new IllegalArgumentException("Radius must be >= 1");
180
-        }
181
-        
182
-        int size = radius * 2 + 1;
183
-        float[] data = new float[size];
184
-        
185
-        float sigma = radius / 3.0f;
186
-        float twoSigmaSquare = 2.0f * sigma * sigma;
187
-        float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
188
-        float total = 0.0f;
189
-        
190
-        for (int i = -radius; i <= radius; i++) {
191
-            float distance = i * i;
192
-            int index = i + radius;
193
-            data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
194
-            total += data[index];
195
-        }
196
-        
197
-        for (int i = 0; i < data.length; i++) {
198
-            data[i] /= total;
199
-        }        
200
-        
201
-        Kernel kernel = null;
202
-        if (horizontal) {
203
-            kernel = new Kernel(size, 1, data);
204
-        } else {
205
-            kernel = new Kernel(1, size, data);
206
-        }
207
-        return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
208
-    }
209
-}

+ 22
- 3
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDialog.java View File

@@ -7,6 +7,8 @@ package org.openzen.drawablegui.swing;
7 7
 
8 8
 import java.awt.BorderLayout;
9 9
 import java.awt.Color;
10
+import java.awt.event.ComponentAdapter;
11
+import java.awt.event.ComponentEvent;
10 12
 import java.awt.event.WindowEvent;
11 13
 import java.awt.event.WindowListener;
12 14
 import java.awt.event.WindowStateListener;
@@ -20,6 +22,7 @@ import org.openzen.drawablegui.DUIWindow;
20 22
 import org.openzen.drawablegui.border.DCustomWindowBorder;
21 23
 import org.openzen.drawablegui.live.LiveBool;
22 24
 import org.openzen.drawablegui.live.LiveObject;
25
+import org.openzen.drawablegui.live.MutableLiveObject;
23 26
 import org.openzen.drawablegui.live.SimpleLiveBool;
24 27
 import org.openzen.drawablegui.live.SimpleLiveObject;
25 28
 import org.openzen.drawablegui.style.DStyleClass;
@@ -33,6 +36,7 @@ public final class SwingDialog extends JDialog implements WindowListener, Window
33 36
 	private final boolean noTitleBar;
34 37
 	private final SimpleLiveObject<State> state = new SimpleLiveObject<>(State.NORMAL);
35 38
 	private final SimpleLiveBool active = new SimpleLiveBool(true);
39
+	private final MutableLiveObject<DIRectangle> bounds = new SimpleLiveObject<>(DIRectangle.EMPTY);
36 40
 	
37 41
 	public SwingDialog(SwingWindow owner, String title, DComponent root, boolean noTitleBar) {
38 42
 		super(owner, title);
@@ -46,6 +50,17 @@ public final class SwingDialog extends JDialog implements WindowListener, Window
46 50
 		
47 51
 		addWindowListener(this);
48 52
 		addWindowStateListener(this);
53
+		addComponentListener(new ComponentAdapter() {
54
+			@Override
55
+			public void componentMoved(ComponentEvent componentEvent) {
56
+				updateBounds();
57
+			}
58
+			
59
+			@Override
60
+			public void componentResized(ComponentEvent componentEvent) {
61
+				updateBounds();
62
+			}
63
+		});
49 64
 		
50 65
 		getContentPane().add(swingComponent = new SwingRoot(root), BorderLayout.CENTER);
51 66
 		swingComponent.setWindow(this);
@@ -76,8 +91,8 @@ public final class SwingDialog extends JDialog implements WindowListener, Window
76 91
 	}
77 92
 
78 93
 	@Override
79
-	public DIRectangle getWindowBounds() {
80
-		return new DIRectangle(getX(), getY(), getWidth(), getHeight());
94
+	public LiveObject<DIRectangle> getWindowBounds() {
95
+		return bounds;
81 96
 	}
82 97
 
83 98
 	@Override
@@ -135,7 +150,7 @@ public final class SwingDialog extends JDialog implements WindowListener, Window
135 150
 
136 151
 	@Override
137 152
 	public void windowOpened(WindowEvent e) {
138
-		
153
+		updateBounds();
139 154
 	}
140 155
 
141 156
 	@Override
@@ -173,6 +188,10 @@ public final class SwingDialog extends JDialog implements WindowListener, Window
173 188
 		state.setValue(getStateFromWindowState());
174 189
 	}
175 190
 	
191
+	private void updateBounds() {
192
+		bounds.setValue(new DIRectangle(getX(), getY(), getWidth(), getHeight()));
193
+	}
194
+	
176 195
 	private State getStateFromWindowState() {
177 196
 		/*switch (ge()) {
178 197
 			case NORMAL:

+ 202
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawSurface.java View File

@@ -0,0 +1,202 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.Font;
9
+import java.awt.Graphics2D;
10
+import java.awt.geom.AffineTransform;
11
+import java.awt.image.ConvolveOp;
12
+import java.awt.image.Kernel;
13
+import java.util.ArrayList;
14
+import java.util.List;
15
+import org.openzen.drawablegui.DFont;
16
+import org.openzen.drawablegui.DFontFamily;
17
+import org.openzen.drawablegui.DFontMetrics;
18
+import org.openzen.drawablegui.DIRectangle;
19
+import org.openzen.drawablegui.DPath;
20
+import org.openzen.drawablegui.DTransform2D;
21
+import org.openzen.drawablegui.draw.DDrawSurface;
22
+import org.openzen.drawablegui.draw.DDrawnRectangle;
23
+import org.openzen.drawablegui.draw.DDrawnShape;
24
+import org.openzen.drawablegui.draw.DDrawnText;
25
+import org.openzen.drawablegui.draw.DSubSurface;
26
+import org.openzen.drawablegui.style.DShadow;
27
+import org.openzen.drawablegui.style.DStyleDefinition;
28
+import org.openzen.drawablegui.style.DStylePath;
29
+
30
+/**
31
+ *
32
+ * @author Hoofdgebruiker
33
+ */
34
+public class SwingDrawSurface implements DDrawSurface {
35
+	private final List<SwingDrawnElement> elements = new ArrayList<>();
36
+	private final SwingGraphicsContext context;
37
+	public int offsetX;
38
+	public int offsetY;
39
+	
40
+	public SwingDrawSurface(SwingGraphicsContext context, int offsetX, int offsetY) {
41
+		this.context = context;
42
+		this.offsetX = offsetX;
43
+		this.offsetY = offsetY;
44
+	}
45
+	
46
+	public void setOffset(int offsetX, int offsetY) {
47
+		this.offsetX = offsetX;
48
+		this.offsetY = offsetY;
49
+	}
50
+	
51
+	public void paint(Graphics2D g, DIRectangle clip) {
52
+		for (SwingDrawnElement element : elements)
53
+			if (clip == null || clip.overlaps(element.getBounds()))
54
+				element.paint(g, clip);
55
+	}
56
+	
57
+	public DIRectangle calculateBounds() {
58
+		if (elements.isEmpty())
59
+			return DIRectangle.EMPTY;
60
+		
61
+		DIRectangle result = elements.get(0).getBounds();
62
+		for (SwingDrawnElement element : elements)
63
+			result = result.union(element.getBounds());
64
+		return result;
65
+	}
66
+
67
+	@Override
68
+	public SwingGraphicsContext getContext() {
69
+		return context;
70
+	}
71
+
72
+	@Override
73
+	public DStyleDefinition getStylesheet(DStylePath path) {
74
+		return context.getStylesheets().get(context, path);
75
+	}
76
+	
77
+	@Override
78
+	public DFontMetrics getFontMetrics(DFont font) {
79
+		return context.getFontMetrics(font);
80
+	}
81
+	
82
+	@Override
83
+	public float getScale() {
84
+		return context.getScale();
85
+	}
86
+	
87
+	@Override
88
+	public float getTextScale() {
89
+		return context.getTextScale();
90
+	}
91
+
92
+	@Override
93
+	public DDrawnText drawText(int z, DFont font, int color, float x, float y, String text) {
94
+		DFontMetrics fontMetrics = context.getFontMetrics(font);
95
+		return addElement(new SwingDrawnText(this, z, x, y, color, font, text, fontMetrics.getAscent(), fontMetrics.getDescent(), fontMetrics.getWidth(text)));
96
+	}
97
+
98
+	@Override
99
+	public DDrawnShape strokePath(int z, DPath path, DTransform2D transform, int color, float lineWidth) {
100
+		return addElement(new SwingStrokedPath(this, z, transform, color, path, context.getPath(path), lineWidth));
101
+	}
102
+	
103
+	@Override
104
+	public DDrawnRectangle fillRect(int z, DIRectangle rectangle, int color) {
105
+		return addElement(new SwingDrawnRectangle(this, z, rectangle, color));
106
+	}
107
+
108
+	@Override
109
+	public DDrawnShape fillPath(int z, DPath path, DTransform2D transform, int color) {
110
+		return addElement(new SwingFilledPath(this, z, transform, path, context.getPath(path), color));
111
+	}
112
+
113
+	@Override
114
+	public DDrawnShape shadowPath(int z, DPath path, DTransform2D transform, int color, DShadow shadow) {
115
+		if (shadow.color == 0 || shadow.radius == 0) {
116
+			return fillPath(z, path, transform, color);
117
+		}
118
+		
119
+		return addElement(new SwingShadowedPath(this, z, transform, path, context.getPath(path), color, shadow));
120
+	}
121
+	
122
+	@Override
123
+	public DSubSurface createSubSurface(int z) {
124
+		return addElement(new SwingSubSurface(this, z));
125
+	}
126
+	
127
+	public void remove(SwingDrawnElement element) {
128
+		elements.remove(element);
129
+		repaint(element.getBounds());
130
+	}
131
+	
132
+	public void repaint(int x, int y, int width, int height) {
133
+		context.repaint(x + offsetX, y + offsetY, width, height);
134
+	}
135
+	
136
+	public void repaint(DIRectangle rectangle) {
137
+		context.repaint(rectangle.offset(offsetX, offsetY));
138
+	}
139
+	
140
+	private <T extends SwingDrawnElement> T addElement(T element) {
141
+		int index = elements.size();
142
+		while (index > 0 && element.z < elements.get(index - 1).z)
143
+			index--;
144
+		
145
+		elements.add(index, element);
146
+		repaint(element.getBounds());
147
+		return element;
148
+	}
149
+	
150
+	public static void prepare(DFont font) {
151
+		if (font.cached != null && font.cached instanceof Font)
152
+			return;
153
+		
154
+		String baseFontName = font.family == DFontFamily.CODE ? "Consolas" : Font.DIALOG;
155
+		int style = 0;
156
+		if (font.bold)
157
+			style |= Font.BOLD;
158
+		if (font.italic)
159
+			style |= Font.ITALIC;
160
+		
161
+		font.cached = Font.decode(baseFontName).deriveFont(style, font.size);
162
+	}
163
+	
164
+	public static AffineTransform getTransform(DTransform2D transform) {
165
+		return new AffineTransform(transform.xx, transform.xy, transform.yx, transform.yy, transform.dx, transform.dy);
166
+	}
167
+    
168
+	
169
+	// taken from http://www.java2s.com/Code/Java/Advanced-Graphics/GaussianBlurDemo.htm
170
+    public static ConvolveOp getGaussianBlurFilter(int radius, boolean horizontal) {
171
+        if (radius < 1) {
172
+            throw new IllegalArgumentException("Radius must be >= 1");
173
+        }
174
+        
175
+        int size = radius * 2 + 1;
176
+        float[] data = new float[size];
177
+        
178
+        float sigma = radius / 3.0f;
179
+        float twoSigmaSquare = 2.0f * sigma * sigma;
180
+        float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
181
+        float total = 0.0f;
182
+        
183
+        for (int i = -radius; i <= radius; i++) {
184
+            float distance = i * i;
185
+            int index = i + radius;
186
+            data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
187
+            total += data[index];
188
+        }
189
+        
190
+        for (int i = 0; i < data.length; i++) {
191
+            data[i] /= total;
192
+        }        
193
+        
194
+        Kernel kernel = null;
195
+        if (horizontal) {
196
+            kernel = new Kernel(size, 1, data);
197
+        } else {
198
+            kernel = new Kernel(1, size, data);
199
+        }
200
+        return new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
201
+    }
202
+}

+ 35
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawnElement.java View File

@@ -0,0 +1,35 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.Graphics2D;
9
+import org.openzen.drawablegui.DIRectangle;
10
+import org.openzen.drawablegui.draw.DDrawnElement;
11
+
12
+/**
13
+ *
14
+ * @author Hoofdgebruiker
15
+ */
16
+public abstract class SwingDrawnElement implements DDrawnElement {
17
+	public final SwingDrawSurface target;
18
+	public final int z;
19
+	
20
+	public SwingDrawnElement(SwingDrawSurface target, int z) {
21
+		this.target = target;
22
+		this.z = z;
23
+	}
24
+	
25
+	abstract void paint(Graphics2D g, DIRectangle clip);
26
+	
27
+	@Override
28
+	public void close() {
29
+		target.remove(this);
30
+	}
31
+	
32
+	protected void invalidate() {
33
+		target.repaint(getBounds());
34
+	}
35
+}

+ 57
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawnRectangle.java View File

@@ -0,0 +1,57 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.Color;
9
+import java.awt.Graphics2D;
10
+import org.openzen.drawablegui.DIRectangle;
11
+import org.openzen.drawablegui.DTransform2D;
12
+import org.openzen.drawablegui.draw.DDrawnRectangle;
13
+
14
+/**
15
+ *
16
+ * @author Hoofdgebruiker
17
+ */
18
+public class SwingDrawnRectangle extends SwingDrawnElement implements DDrawnRectangle {
19
+	private DIRectangle rectangle;
20
+	private Color awtColor;
21
+	
22
+	public SwingDrawnRectangle(SwingDrawSurface target, int z, DIRectangle rectangle, int color) {
23
+		super(target, z);
24
+		
25
+		this.rectangle = rectangle;
26
+		this.awtColor = new Color(color, true);
27
+	}
28
+	
29
+	@Override
30
+	public void setTransform(DTransform2D transform) {
31
+		// not supported?
32
+	}
33
+	
34
+	@Override
35
+	public DIRectangle getBounds() {
36
+		return rectangle;
37
+	}
38
+
39
+	@Override
40
+	public void setRectangle(DIRectangle rectangle) {
41
+		invalidate();
42
+		this.rectangle = rectangle;
43
+		invalidate();
44
+	}
45
+
46
+	@Override
47
+	public void setColor(int color) {
48
+		this.awtColor = new Color(color, true);
49
+		invalidate();
50
+	}
51
+
52
+	@Override
53
+	public void paint(Graphics2D g, DIRectangle clip) {
54
+		g.setColor(awtColor);
55
+		g.fillRect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
56
+	}
57
+}

+ 68
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingDrawnText.java View File

@@ -0,0 +1,68 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.Color;
9
+import java.awt.Font;
10
+import java.awt.Graphics2D;
11
+import org.openzen.drawablegui.DFont;
12
+import org.openzen.drawablegui.DIRectangle;
13
+import org.openzen.drawablegui.draw.DDrawnText;
14
+
15
+/**
16
+ *
17
+ * @author Hoofdgebruiker
18
+ */
19
+public class SwingDrawnText extends SwingDrawnElement implements DDrawnText {
20
+	private float x;
21
+	private float y;
22
+	private final int width;
23
+	private final int ascent;
24
+	private final int descent;
25
+	private Color awtColor;
26
+	private final Font font;
27
+	private final String text;
28
+	
29
+	public SwingDrawnText(SwingDrawSurface target, int z, float x, float y, int color, DFont font, String text, int ascent, int descent, int width) {
30
+		super(target, z);
31
+		SwingDrawSurface.prepare(font);
32
+		
33
+		this.x = x;
34
+		this.y = y;
35
+		this.awtColor = new Color(color, true);
36
+		this.font = (Font) font.cached;
37
+		this.text = text;
38
+		this.ascent = ascent;
39
+		this.descent = descent;
40
+		this.width = width;
41
+	}
42
+
43
+	@Override
44
+	public void setPosition(float x, float y) {
45
+		invalidate();
46
+		this.x = x;
47
+		this.y = y;
48
+		invalidate();
49
+	}
50
+
51
+	@Override
52
+	public DIRectangle getBounds() {
53
+		return new DIRectangle((int)x, (int)y - ascent, width, ascent + descent);
54
+	}
55
+	
56
+	@Override
57
+	public void setColor(int color) {
58
+		this.awtColor = new Color(color, true);
59
+		invalidate();
60
+	}
61
+
62
+	@Override
63
+	public void paint(Graphics2D g, DIRectangle clip) {
64
+		g.setColor(awtColor);
65
+		g.setFont(font);
66
+		g.drawString(text, x, y);
67
+	}
68
+}

+ 75
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingFilledPath.java View File

@@ -0,0 +1,75 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.Color;
9
+import java.awt.Graphics2D;
10
+import java.awt.geom.AffineTransform;
11
+import java.awt.geom.GeneralPath;
12
+import org.openzen.drawablegui.DIRectangle;
13
+import org.openzen.drawablegui.DPath;
14
+import org.openzen.drawablegui.DPathBoundsCalculator;
15
+import org.openzen.drawablegui.DTransform2D;
16
+import org.openzen.drawablegui.draw.DDrawnShape;
17
+
18
+/**
19
+ *
20
+ * @author Hoofdgebruiker
21
+ */
22
+public class SwingFilledPath extends SwingDrawnElement implements DDrawnShape {
23
+	private Color awtColor;
24
+	private AffineTransform transform;
25
+	
26
+	private final DPath originalPath;
27
+	private final GeneralPath path;
28
+	private DIRectangle bounds;
29
+	
30
+	public SwingFilledPath(
31
+			SwingDrawSurface target,
32
+			int z,
33
+			DTransform2D transform,
34
+			DPath originalPath,
35
+			GeneralPath path,
36
+			int color) {
37
+		super(target, z);
38
+		
39
+		this.originalPath = originalPath;
40
+		this.path = path;
41
+		
42
+		this.awtColor = color == 0 ? null : new Color(color, true);
43
+		this.transform = SwingDrawSurface.getTransform(transform);
44
+		this.bounds = DPathBoundsCalculator.getBounds(originalPath, transform);
45
+	}
46
+
47
+	@Override
48
+	public void setTransform(DTransform2D transform) {
49
+		this.transform = SwingDrawSurface.getTransform(transform);
50
+		this.bounds = DPathBoundsCalculator.getBounds(originalPath, transform);
51
+	}
52
+	
53
+	@Override
54
+	public DIRectangle getBounds() {
55
+		return bounds;
56
+	}
57
+
58
+	@Override
59
+	public void setColor(int color) {
60
+		this.awtColor = color == 0 ? null : new Color(color, true);
61
+		invalidate();
62
+	}
63
+
64
+	@Override
65
+	public void paint(Graphics2D g, DIRectangle clip) {
66
+		if (awtColor == null)
67
+			return;
68
+		
69
+		AffineTransform old = g.getTransform();
70
+		g.setColor(awtColor);
71
+		g.transform(transform);
72
+		g.fill(path);
73
+		g.setTransform(old);
74
+	}
75
+}

+ 29
- 19
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingGraphicsContext.java View File

@@ -8,6 +8,7 @@ package org.openzen.drawablegui.swing;
8 8
 import java.awt.Dimension;
9 9
 import java.awt.Font;
10 10
 import java.awt.Graphics;
11
+import java.awt.Point;
11 12
 import java.awt.geom.GeneralPath;
12 13
 import java.util.WeakHashMap;
13 14
 import javax.swing.JFrame;
@@ -21,10 +22,9 @@ import org.openzen.drawablegui.DFont;
21 22
 import org.openzen.drawablegui.DFontMetrics;
22 23
 import org.openzen.drawablegui.DPathTracer;
23 24
 import org.openzen.drawablegui.DTimerHandle;
24
-import org.openzen.drawablegui.DTooltip;
25
-import org.openzen.drawablegui.DTooltipHandle;
26 25
 import org.openzen.drawablegui.DUIContext;
27 26
 import org.openzen.drawablegui.DUIWindow;
27
+import org.openzen.drawablegui.draw.DDrawSurface;
28 28
 import org.openzen.drawablegui.style.DStylePathRoot;
29 29
 import org.openzen.drawablegui.style.DStyleSheets;
30 30
 
@@ -41,6 +41,7 @@ public class SwingGraphicsContext implements DUIContext {
41 41
 	private final JavaClipboard clipboard = new JavaClipboard();
42 42
 	private Graphics graphics;
43 43
 	private DUIWindow window;
44
+	private DDrawSurface surface;
44 45
 	
45 46
 	public SwingGraphicsContext(DStyleSheets stylesheets, float scale, float textScale, SwingRoot root) {
46 47
 		this.stylesheets = stylesheets;
@@ -49,6 +50,10 @@ public class SwingGraphicsContext implements DUIContext {
49 50
 		this.root = root;
50 51
 	}
51 52
 	
53
+	public void setSurface(DDrawSurface surface) {
54
+		this.surface = surface;
55
+	}
56
+	
52 57
 	public GeneralPath getPath(DPath path) {
53 58
 		GeneralPath generalPath = preparedPaths.get(path);
54 59
 		if (generalPath == null) {
@@ -123,7 +128,7 @@ public class SwingGraphicsContext implements DUIContext {
123 128
 		if (graphics == null)
124 129
 			throw new AssertionError("No graphics available!");
125 130
 		
126
-		SwingCanvas.prepare(font);
131
+		SwingDrawSurface.prepare(font);
127 132
 		return new SwingFontMetrics(graphics.getFontMetrics((Font) font.cached), graphics);
128 133
 	}
129 134
 
@@ -151,15 +156,19 @@ public class SwingGraphicsContext implements DUIContext {
151 156
 
152 157
 	@Override
153 158
 	public DUIWindow openDialog(int x, int y, DAnchor anchor, String title, DComponent root) {
154
-		SwingDialog window = new SwingDialog((SwingWindow)this.window, title, root, false);
155
-		SwingGraphicsContext windowContext = new SwingGraphicsContext(stylesheets, scale, textScale, window.swingComponent);
159
+		SwingWindow swingWindow = (SwingWindow)this.window;
160
+		SwingDialog window = new SwingDialog(swingWindow, title, root, false);
161
+		SwingGraphicsContext windowContext = window.swingComponent.context;
156 162
 		windowContext.setWindow(window);
157 163
 		windowContext.graphics = this.graphics; // help a little...
164
+		windowContext.setSurface(window.swingComponent.surface);
165
+		
166
+		Point rootLocation = swingWindow.swingComponent.getLocationOnScreen();
158 167
 		
159
-		root.setContext(DStylePathRoot.INSTANCE, windowContext);
168
+		root.mount(DStylePathRoot.INSTANCE, 0, windowContext.surface);
160 169
 		DSizing dimension = root.getSizing().getValue();
161
-		int tx = (int)(x - anchor.alignX * dimension.preferredWidth);
162
-		int ty = (int)(y - anchor.alignY * dimension.preferredHeight);
170
+		int tx = (int)(x + rootLocation.x - anchor.alignX * dimension.preferredWidth);
171
+		int ty = (int)(y + rootLocation.y - anchor.alignY * dimension.preferredHeight);
163 172
 		
164 173
 		window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
165 174
 		window.swingComponent.setPreferredSize(new Dimension(dimension.preferredWidth, dimension.preferredHeight));
@@ -171,29 +180,30 @@ public class SwingGraphicsContext implements DUIContext {
171 180
 
172 181
 	@Override
173 182
 	public DUIWindow openView(int x, int y, DAnchor anchor, DComponent root) {
174
-		SwingDialog window = new SwingDialog((SwingWindow)this.window, "", root, false);
175
-		SwingGraphicsContext windowContext = new SwingGraphicsContext(stylesheets, scale, textScale, window.swingComponent);
183
+		SwingWindow swingWindow = (SwingWindow)this.window;
184
+		SwingInlineWindow window = new SwingInlineWindow(swingWindow, "", root);
185
+		SwingGraphicsContext windowContext = window.swingComponent.context;
176 186
 		windowContext.setWindow(window);
177 187
 		windowContext.graphics = this.graphics; // help a little...
188
+		windowContext.setSurface(window.swingComponent.surface);
178 189
 		
179
-		root.setContext(DStylePathRoot.INSTANCE, windowContext);
190
+		root.mount(DStylePathRoot.INSTANCE, 0, windowContext.surface);
180 191
 		DSizing dimension = root.getSizing().getValue();
181
-		int tx = (int)(x - anchor.alignX * dimension.preferredWidth);
182
-		int ty = (int)(y - anchor.alignY * dimension.preferredHeight);
183 192
 		
184
-		window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
193
+		Point rootLocation = swingWindow.swingComponent.getLocationOnScreen();
194
+		
195
+		int tx = (int)(x + rootLocation.x - anchor.alignX * dimension.preferredWidth);
196
+		int ty = (int)(y + rootLocation.y - anchor.alignY * dimension.preferredHeight);
197
+		
185 198
 		window.swingComponent.setPreferredSize(new Dimension(dimension.preferredWidth, dimension.preferredHeight));
186 199
 		window.setLocation(tx, ty);
187 200
 		window.pack();
188 201
 		window.setVisible(true);
202
+		window.swingComponent.repaint();
203
+		
189 204
 		return window;
190 205
 	}
191 206
 	
192
-	@Override
193
-	public DTooltipHandle openTooltip(int x, int y, DTooltip tooltip) {
194
-		return null; // TODO
195
-	}
196
-	
197 207
 	private class PathTracer implements DPathTracer {
198 208
 		private final GeneralPath path;
199 209
 		

+ 156
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingInlineWindow.java View File

@@ -0,0 +1,156 @@
1
+/*
2
+ * To change this license header, choose License Headers in Project Properties.
3
+ * To change this template file, choose Tools | Templates
4
+ * and open the template in the editor.
5
+ */
6
+package org.openzen.drawablegui.swing;
7
+
8
+import java.awt.BorderLayout;
9
+import java.awt.event.ComponentAdapter;
10
+import java.awt.event.ComponentEvent;
11
+import java.awt.event.WindowEvent;
12
+import java.awt.event.WindowListener;
13
+import java.awt.event.WindowStateListener;
14
+import javax.swing.JWindow;
15
+import org.openzen.drawablegui.DComponent;
16
+import org.openzen.drawablegui.DIRectangle;
17
+import org.openzen.drawablegui.DUIContext;
18
+import org.openzen.drawablegui.DUIWindow;
19
+import org.openzen.drawablegui.live.ImmutableLiveObject;
20
+import org.openzen.drawablegui.live.LiveBool;
21
+import org.openzen.drawablegui.live.LiveObject;
22
+import org.openzen.drawablegui.live.MutableLiveObject;
23
+import org.openzen.drawablegui.live.SimpleLiveBool;
24
+import org.openzen.drawablegui.live.SimpleLiveObject;
25
+
26
+/**
27
+ *
28
+ * @author Hoofdgebruiker
29
+ */
30
+public final class SwingInlineWindow extends JWindow implements WindowListener, WindowStateListener, DUIWindow {
31
+	public final SwingRoot swingComponent;
32
+	private final LiveObject<State> state = new ImmutableLiveObject<>(State.NORMAL);
33
+	private final SimpleLiveBool active = new SimpleLiveBool(true);
34
+	private final MutableLiveObject<DIRectangle> bounds = new SimpleLiveObject<>(DIRectangle.EMPTY);
35
+	
36
+	public SwingInlineWindow(SwingWindow owner, String title, DComponent root) {
37
+		super(owner);
38
+		
39
+		addWindowListener(this);
40
+		addWindowStateListener(this);
41
+		
42
+		getContentPane().add(swingComponent = new SwingRoot(root), BorderLayout.CENTER);
43
+		swingComponent.setWindow(this);
44
+		swingComponent.requestFocusInWindow();
45
+		addComponentListener(new ComponentAdapter() {
46
+			@Override
47
+			public void componentMoved(ComponentEvent componentEvent) {
48
+				updateBounds();
49
+			}
50
+			
51
+			@Override
52
+			public void componentResized(ComponentEvent componentEvent) {
53
+				updateBounds();
54
+			}
55
+		});
56
+	}
57
+	
58
+	@Override
59
+	public DUIContext getContext() {
60
+		return swingComponent.context;
61
+	}
62
+
63
+	@Override
64
+	public LiveObject<DIRectangle> getWindowBounds() {
65
+		return bounds;
66
+	}
67
+
68
+	@Override
69
+	public boolean hasTitleBar() {
70
+		return false;
71
+	}
72
+
73
+	@Override
74
+	public void close() {
75
+		dispose();
76
+	}
77
+
78
+	@Override
79
+	public void maximize() {
80
+		// cannot maximize
81
+	}
82
+
83
+	@Override
84
+	public void restore() {
85
+		// cannot restore
86
+	}
87
+
88
+	@Override
89
+	public void minimize() {
90
+		// cannot minimize
91
+	}
92
+
93
+	@Override
94
+	public LiveObject<State> getWindowState() {
95
+		return state;
96
+	}
97
+	
98
+	@Override
99
+	public LiveBool getActive() {
100
+		return active;
101
+	}
102
+	
103
+	@Override
104
+	public void focus(DComponent component) {
105
+		swingComponent.focus(component);
106
+	}
107
+	
108
+	@Override
109
+	public DUIWindow openModal(String title, DComponent component) {
110
+		throw new IllegalArgumentException("Cannot open a modal from an inline window!");
111
+	}
112
+
113
+	@Override
114
+	public void windowOpened(WindowEvent e) {
115
+		updateBounds();
116
+	}
117
+
118
+	@Override
119
+	public void windowClosing(WindowEvent e) {
120
+		
121
+	}
122
+
123
+	@Override
124
+	public void windowClosed(WindowEvent e) {
125
+		
126
+	}
127
+
128
+	@Override
129
+	public void windowIconified(WindowEvent e) {
130
+		
131
+	}
132
+
133
+	@Override
134
+	public void windowDeiconified(WindowEvent e) {
135
+		
136
+	}
137
+
138
+	@Override
139
+	public void windowActivated(WindowEvent e) {
140
+		active.setValue(true);
141
+	}
142
+
143
+	@Override
144
+	public void windowDeactivated(WindowEvent e) {
145
+		active.setValue(false);
146
+	}
147
+
148
+	@Override
149
+	public void windowStateChanged(WindowEvent e) {
150
+		
151
+	}
152
+	
153
+	private void updateBounds() {
154
+		bounds.setValue(new DIRectangle(getX(), getY(), getWidth(), getHeight()));
155
+	}
156
+}

+ 15
- 3
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingRoot.java View File

@@ -9,6 +9,7 @@ import java.awt.Component;
9 9
 import java.awt.Graphics;
10 10
 import java.awt.Graphics2D;
11 11
 import java.awt.Rectangle;
12
+import java.awt.RenderingHints;
12 13
 import java.awt.Toolkit;
13 14
 import java.awt.event.ComponentEvent;
14 15
 import java.awt.event.ComponentListener;
@@ -34,6 +35,7 @@ import org.openzen.drawablegui.style.DStylePathRoot;
34 35
  */
35 36
 public final class SwingRoot extends Component implements ComponentListener, MouseListener, MouseMotionListener, MouseWheelListener, KeyListener {
36 37
 	public final SwingGraphicsContext context;
38
+	public final SwingDrawSurface surface;
37 39
 	public final DComponent component;
38 40
 	private DComponent focus = null;
39 41
 	private boolean firstPaint = true;
@@ -48,6 +50,8 @@ public final class SwingRoot extends Component implements ComponentListener, Mou
48 50
 				Toolkit.getDefaultToolkit().getScreenResolution() / 96.0f,
49 51
 				Toolkit.getDefaultToolkit().getScreenResolution() / 96.0f,
50 52
 				this);
53
+		surface = new SwingDrawSurface(context, 0, 0);
54
+		context.setSurface(surface);
51 55
 		
52 56
 		addComponentListener(this);
53 57
 		addMouseListener(this);
@@ -75,18 +79,26 @@ public final class SwingRoot extends Component implements ComponentListener, Mou
75 79
 	public void paint(Graphics g) {
76 80
 		if (firstPaint) {
77 81
 			firstPaint = false;
78
-			component.setContext(DStylePathRoot.INSTANCE, context);
82
+			component.mount(DStylePathRoot.INSTANCE, 0, surface);
79 83
 			component.setBounds(new DIRectangle(0, 0, getWidth(), getHeight()));
80 84
 		}
81 85
 		
86
+		long start = System.currentTimeMillis();
82 87
 		Rectangle clipBounds = g.getClipBounds();
83 88
 		DIRectangle clipBounds2 = clipBounds == null ? null : new DIRectangle(clipBounds.x, clipBounds.y, clipBounds.width, clipBounds.height);
84
-		SwingCanvas canvas = new SwingCanvas((Graphics2D) g, context, clipBounds2);
85
-		component.paint(canvas);
89
+		Graphics2D g2d = (Graphics2D) g;
90
+		g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
91
+		g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
92
+		surface.paint(g2d, clipBounds2);
93
+		
94
+		System.out.println("Paint in " + (System.currentTimeMillis() - start) + " ms, bounds: " + clipBounds.toString());
86 95
 	}
87 96
 
88 97
 	@Override
89 98
 	public void componentResized(ComponentEvent e) {
99
+		if (firstPaint)
100
+			return;
101
+		
90 102
 		component.setBounds(new DIRectangle(0, 0,
91 103
 				e.getComponent().getWidth(),
92 104
 				e.getComponent().getHeight()));

+ 0
- 0
DrawableGui/src/main/java/org/openzen/drawablegui/swing/SwingShadowedPath.java View File


Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save