From 6a910b9ba5443aa31f7cc2468c943c2f9da4854b Mon Sep 17 00:00:00 2001
From: Nate Symer <nate@symer.io>
Date: Sat, 9 Jun 2018 09:34:56 -0400
Subject: Implement gaps (PR #2047)

---
 sway/commands/gaps.c       | 183 +++++++++++++++++++++++++++++++++++++++++++++
 sway/commands/smart_gaps.c |  28 +++++++
 2 files changed, 211 insertions(+)
 create mode 100644 sway/commands/gaps.c
 create mode 100644 sway/commands/smart_gaps.c

(limited to 'sway/commands')

diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c
new file mode 100644
index 00000000..aacb792b
--- /dev/null
+++ b/sway/commands/gaps.c
@@ -0,0 +1,183 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/arrange.h"
+#include "log.h"
+#include "stringop.h"
+#include <math.h>
+
+enum gaps_op {
+	GAPS_OP_SET,
+	GAPS_OP_ADD,
+	GAPS_OP_SUBTRACT
+};
+
+enum gaps_scope {
+	GAPS_SCOPE_ALL,
+	GAPS_SCOPE_WORKSPACE,
+	GAPS_SCOPE_CURRENT
+};
+
+struct cmd_results *cmd_gaps(int argc, char **argv) {
+	struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 1);
+	if (error) {
+		return error;
+	}
+
+	if (strcmp(argv[0], "edge_gaps") == 0) {
+		if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) {
+			return error;
+		}
+
+		if (strcmp(argv[1], "on") == 0) {
+			config->edge_gaps = true;
+			arrange_root();
+		} else if (strcmp(argv[1], "off") == 0) {
+			config->edge_gaps = false;
+			arrange_root();
+		} else if (strcmp(argv[1], "toggle") == 0) {
+			if (!config->active) {
+				return cmd_results_new(CMD_INVALID, "gaps",
+					"Cannot toggle gaps while not running.");
+			}
+			config->edge_gaps = !config->edge_gaps;
+			arrange_root();
+		} else {
+			return cmd_results_new(CMD_INVALID, "gaps",
+				"gaps edge_gaps on|off|toggle");
+		}
+	} else {
+		int amount_idx = 0; // the current index in argv
+		enum gaps_op op = GAPS_OP_SET;
+		enum gaps_scope scope = GAPS_SCOPE_ALL;
+		bool inner = true;
+
+		if (strcmp(argv[0], "inner") == 0) {
+			amount_idx++;
+			inner = true;
+		} else if (strcmp(argv[0], "outer") == 0) {
+			amount_idx++;
+			inner = false;
+		}
+
+		// If one of the long variants of the gaps command is used
+		// (which starts with inner|outer) check the number of args
+		if (amount_idx > 0) { // if we've seen inner|outer
+			if (argc > 2) { // check the longest variant
+				error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4);
+				if (error) {
+					return error;
+				}
+			} else { // check the next longest format
+				error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2);
+				if (error) {
+					return error;
+				}
+			}
+		} else {
+			error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 1);
+			if (error) {
+				return error;
+			}
+		}
+
+		if (argc == 4) {
+			// Long format: all|workspace|current.
+			if (strcmp(argv[amount_idx], "all") == 0) {
+				amount_idx++;
+				scope = GAPS_SCOPE_ALL;
+			} else if (strcmp(argv[amount_idx], "workspace") == 0) {
+				amount_idx++;
+				scope = GAPS_SCOPE_WORKSPACE;
+			} else if (strcmp(argv[amount_idx], "current") == 0) {
+				amount_idx++;
+				scope = GAPS_SCOPE_CURRENT;
+			}
+
+			// Long format: set|plus|minus
+			if (strcmp(argv[amount_idx], "set") == 0) {
+				amount_idx++;
+				op = GAPS_OP_SET;
+			} else if (strcmp(argv[amount_idx], "plus") == 0) {
+				amount_idx++;
+				op = GAPS_OP_ADD;
+			} else if (strcmp(argv[amount_idx], "minus") == 0) {
+				amount_idx++;
+				op = GAPS_OP_SUBTRACT;
+			}
+		}
+
+		char *end;
+		double val = strtod(argv[amount_idx], &end);
+
+		if (strlen(end) && val == 0.0) { // invalid <amount>
+			// guess which variant of the command was attempted
+			if (argc == 1) {
+				return cmd_results_new(CMD_INVALID, "gaps", "gaps <amount>");
+			}
+			if (argc == 2) {
+				return cmd_results_new(CMD_INVALID, "gaps",
+					"gaps inner|outer <amount>");
+			}
+			return cmd_results_new(CMD_INVALID, "gaps",
+				"gaps inner|outer all|workspace|current set|plus|minus <amount>"); 
+		}
+
+		if (amount_idx == 0) { // gaps <amount>
+			config->gaps_inner = val;
+			config->gaps_outer = val;
+			arrange_root();
+			return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+		}
+		// Other variants. The middle-length variant (gaps inner|outer <amount>)
+		// just defaults the scope to "all" and defaults the op to "set".
+
+		double total;
+		switch (op) {
+			case GAPS_OP_SUBTRACT: {
+				total = (inner ? config->gaps_inner : config->gaps_outer) - val;
+				if (total < 0) {
+					total = 0;
+				}
+				break;
+			}
+			case GAPS_OP_ADD: {
+				total = (inner ? config->gaps_inner : config->gaps_outer) + val;
+				break;
+			}
+			case GAPS_OP_SET: {
+				total = val;
+				break;
+			}
+		}
+ 
+		if (scope == GAPS_SCOPE_ALL) {
+			if (inner) {
+				config->gaps_inner = total;
+			} else {
+				config->gaps_outer = total;
+			}
+			arrange_root();
+		} else {
+			struct sway_container *c =
+				config->handler_context.current_container;
+			if (scope == GAPS_SCOPE_WORKSPACE && c->type != C_WORKSPACE) {
+				c = container_parent(c, C_WORKSPACE);
+			}
+			c->has_gaps = true;
+			if (inner) {
+				c->gaps_inner = total;
+			} else {
+				c->gaps_outer = total;
+			}
+
+			if (c->parent) {
+				arrange_children_of(c->parent);
+			} else {
+				arrange_root();
+			}
+		}
+	}
+
+	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c
new file mode 100644
index 00000000..38700d65
--- /dev/null
+++ b/sway/commands/smart_gaps.c
@@ -0,0 +1,28 @@
+#include <string.h>
+#include "sway/commands.h"
+#include "sway/config.h"
+#include "sway/tree/arrange.h"
+#include "sway/tree/view.h"
+#include "sway/tree/container.h"
+#include "log.h"
+#include "stringop.h"
+
+struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
+	struct cmd_results *error = checkarg(argc, "smart_gaps", EXPECTED_AT_LEAST, 1);
+
+	if (error) {
+		return error;
+	}
+
+	if (strcmp(argv[0], "on") == 0) {
+		config->smart_gaps = true;
+		arrange_root();
+	} else if (strcmp(argv[0], "off") == 0) {
+		config->smart_gaps = false;
+		arrange_root();
+	} else {
+		return cmd_results_new(CMD_INVALID, "smart_gaps",
+			"Expected 'smart_gaps <on|off>' ");
+	}
+	return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+}
-- 
cgit v1.2.3