shithub: microui

Download patch

ref: dd374fc9c9980c6440845e4f4df7792ec4b4aaf0
parent: 98df47ce03d260c7e15e7f3bcec04a1ace8d180c
author: Sigrid Haflínudóttir <[email protected]>
date: Mon Jan 6 20:08:00 EST 2020

dynamic allocation, reformatting

--- a/demo/frame.c
+++ b/demo/frame.c
@@ -4,221 +4,234 @@
 #include "microui.h"
 
 static char logbuf[64000];
-static  int logbuf_updated = 0;
+static int logbuf_updated = 0;
 
-static void write_log(const char *text) {
-  if (logbuf[0]) { strcat(logbuf, "\n"); }
-  strcat(logbuf, text);
-  logbuf_updated = 1;
+static void
+write_log(const char *text)
+{
+	if (logbuf[0])
+		strcat(logbuf, "\n");
+	strcat(logbuf, text);
+	logbuf_updated = 1;
 }
 
 #define text_width(s) (stringwidth(ctx->style->font, s) + 6)
 #define text_height() ctx->style->font->height
+#define max(a, b) ((a) > (b) ? (a) : (b))
 
-static void test_window(mu_Context *ctx) {
-  static mu_Container window;
+static void
+test_window(mu_Context *ctx)
+{
+	static mu_Container window;
 
-  /* init window manually so we can set its position and size */
-  if (!window.inited) {
-    mu_init_window(ctx, &window, 0);
-    window.rect = mu_rect(40, 40, 320, 500);
-  }
+	/* init window manually so we can set its position and size */
+	if (!window.inited) {
+		mu_init_window(ctx, &window, 0);
+		window.rect = mu_rect(40, 40, 320, 500);
+	}
 
-  /* limit window to minimum size */
-  window.rect.w = mu_max(window.rect.w, 240);
-  window.rect.h = mu_max(window.rect.h, 300);
+	/* limit window to minimum size */
+	window.rect.w = max(window.rect.w, 240);
+	window.rect.h = max(window.rect.h, 300);
 
+	/* do window */
+	if (mu_begin_window(ctx, &window, "Demo Window")) {
 
-  /* do window */
-  if (mu_begin_window(ctx, &window, "Demo Window")) {
+		/* window info */
+		static int show_info = 0;
+		if (mu_header(ctx, &show_info, "Window Info")) {
+			char buf[64];
+			const int widths[] = { text_width("Position:"), -1 };
+			mu_layout_row(ctx, 2, widths, 0);
+			mu_label(ctx, "Position:");
+			sprint(buf, "%d, %d", window.rect.x, window.rect.y); mu_label(ctx, buf);
+			mu_label(ctx, "Size:");
+			sprint(buf, "%d, %d", window.rect.w, window.rect.h); mu_label(ctx, buf);
+		}
 
-    /* window info */
-    static int show_info = 0;
-    if (mu_header(ctx, &show_info, "Window Info")) {
-      char buf[64];
-      const int widths[] = { text_width("Position:"), -1 };
-      mu_layout_row(ctx, 2, widths, 0);
-      mu_label(ctx, "Position:");
-      sprint(buf, "%d, %d", window.rect.x, window.rect.y); mu_label(ctx, buf);
-      mu_label(ctx, "Size:");
-      sprint(buf, "%d, %d", window.rect.w, window.rect.h); mu_label(ctx, buf);
-    }
+		/* labels + buttons */
+		static int show_buttons = 1;
+		if (mu_header(ctx, &show_buttons, "Test Buttons")) {
+			const int widths[] = { text_width("Test buttons 2:"), -text_width("Button 2	"), -1 };
+			mu_layout_row(ctx, 3, widths, 0);
+			mu_label(ctx, "Test buttons 1:");
+			if (mu_button(ctx, "Button 1")) { write_log("Pressed button 1"); }
+			if (mu_button(ctx, "Button 2")) { write_log("Pressed button 2"); }
+			mu_label(ctx, "Test buttons 2:");
+			if (mu_button(ctx, "Button 3")) { write_log("Pressed button 3"); }
+			if (mu_button(ctx, "Button 4")) { write_log("Pressed button 4"); }
+		}
 
-    /* labels + buttons */
-    static int show_buttons = 1;
-    if (mu_header(ctx, &show_buttons, "Test Buttons")) {
-      const int widths[] = { 86, -110, -1 };
-      mu_layout_row(ctx, 3, widths, 0);
-      mu_label(ctx, "Test buttons 1:");
-      if (mu_button(ctx, "Button 1")) { write_log("Pressed button 1"); }
-      if (mu_button(ctx, "Button 2")) { write_log("Pressed button 2"); }
-      mu_label(ctx, "Test buttons 2:");
-      if (mu_button(ctx, "Button 3")) { write_log("Pressed button 3"); }
-      if (mu_button(ctx, "Button 4")) { write_log("Pressed button 4"); }
-    }
+		/* tree */
+		static int show_tree = 1;
+		if (mu_header(ctx, &show_tree, "Tree and Text")) {
+			int widths[] = { text_width("Test 1a")+text_height()*2+text_width("Button 3")+6, -1 };
+			mu_layout_row(ctx, 2, widths, 0);
+			mu_layout_begin_column(ctx);
+			static int states[8];
+			if (mu_begin_treenode(ctx, &states[0], "Test 1")) {
+				if (mu_begin_treenode(ctx, &states[1], "Test 1a")) {
+					mu_label(ctx, "Hello");
+					mu_label(ctx, "world");
+					mu_end_treenode(ctx);
+				}
+				if (mu_begin_treenode(ctx, &states[2], "Test 1b")) {
+					if (mu_button(ctx, "Button 1")) { write_log("Pressed button 1"); }
+					if (mu_button(ctx, "Button 2")) { write_log("Pressed button 2"); }
+					mu_end_treenode(ctx);
+				}
+				mu_end_treenode(ctx);
+			}
+			if (mu_begin_treenode(ctx, &states[3], "Test 2")) {
+				int widths[2];
+				widths[0] = widths[1] = text_width("Button 3");
+				mu_layout_row(ctx, 2, widths, 0);
+				if (mu_button(ctx, "Button 3")) { write_log("Pressed button 3"); }
+				if (mu_button(ctx, "Button 4")) { write_log("Pressed button 4"); }
+				if (mu_button(ctx, "Button 5")) { write_log("Pressed button 5"); }
+				if (mu_button(ctx, "Button 6")) { write_log("Pressed button 6"); }
+				mu_end_treenode(ctx);
+			}
+			if (mu_begin_treenode(ctx, &states[4], "Test 3")) {
+				static int checks[3] = { 1, 0, 1 };
+				mu_checkbox(ctx, &checks[0], "Checkbox 1");
+				mu_checkbox(ctx, &checks[1], "Checkbox 2");
+				mu_checkbox(ctx, &checks[2], "Checkbox 3");
+				mu_end_treenode(ctx);
+			}
+			mu_layout_end_column(ctx);
 
-    /* tree */
-    static int show_tree = 1;
-    if (mu_header(ctx, &show_tree, "Tree and Text")) {
-      int widths[] = { text_width("Test 1a")+text_height()*2+text_width("Button 3")+6, -1 };
-      mu_layout_row(ctx, 2, widths, 0);
-      mu_layout_begin_column(ctx);
-      static int states[8];
-      if (mu_begin_treenode(ctx, &states[0], "Test 1")) {
-        if (mu_begin_treenode(ctx, &states[1], "Test 1a")) {
-          mu_label(ctx, "Hello");
-          mu_label(ctx, "world");
-          mu_end_treenode(ctx);
-        }
-        if (mu_begin_treenode(ctx, &states[2], "Test 1b")) {
-          if (mu_button(ctx, "Button 1")) { write_log("Pressed button 1"); }
-          if (mu_button(ctx, "Button 2")) { write_log("Pressed button 2"); }
-          mu_end_treenode(ctx);
-        }
-        mu_end_treenode(ctx);
-      }
-      if (mu_begin_treenode(ctx, &states[3], "Test 2")) {
-        int widths[2];
-        widths[0] = widths[1] = text_width("Button 3");
-        mu_layout_row(ctx, 2, widths, 0);
-        if (mu_button(ctx, "Button 3")) { write_log("Pressed button 3"); }
-        if (mu_button(ctx, "Button 4")) { write_log("Pressed button 4"); }
-        if (mu_button(ctx, "Button 5")) { write_log("Pressed button 5"); }
-        if (mu_button(ctx, "Button 6")) { write_log("Pressed button 6"); }
-        mu_end_treenode(ctx);
-      }
-      if (mu_begin_treenode(ctx, &states[4], "Test 3")) {
-        static int checks[3] = { 1, 0, 1 };
-        mu_checkbox(ctx, &checks[0], "Checkbox 1");
-        mu_checkbox(ctx, &checks[1], "Checkbox 2");
-        mu_checkbox(ctx, &checks[2], "Checkbox 3");
-        mu_end_treenode(ctx);
-      }
-      mu_layout_end_column(ctx);
+			mu_layout_begin_column(ctx);
+			widths[0] = -1;
+			mu_layout_row(ctx, 1, widths, 0);
+			mu_text(ctx, "Lorem ipsum dolor sit amet, consectetur adipiscing "
+				"elit. Maecenas lacinia, sem eu lacinia molestie, mi risus faucibus "
+				"ipsum, eu varius magna felis a nulla.");
+			mu_layout_end_column(ctx);
+		}
 
-      mu_layout_begin_column(ctx);
-      widths[0] = -1;
-      mu_layout_row(ctx, 1, widths, 0);
-      mu_text(ctx, "Lorem ipsum dolor sit amet, consectetur adipiscing "
-        "elit. Maecenas lacinia, sem eu lacinia molestie, mi risus faucibus "
-        "ipsum, eu varius magna felis a nulla.");
-      mu_layout_end_column(ctx);
-    }
-
-    mu_end_window(ctx);
-  }
+		mu_end_window(ctx);
+	}
 }
 
 
-static void log_window(mu_Context *ctx) {
-  static mu_Container window;
+static void
+log_window(mu_Context *ctx)
+{
+	static mu_Container window;
 
-  /* init window manually so we can set its position and size */
-  if (!window.inited) {
-    mu_init_window(ctx, &window, 0);
-    window.rect = mu_rect(370, 40, 340, 200);
-  }
+	/* init window manually so we can set its position and size */
+	if (!window.inited) {
+		mu_init_window(ctx, &window, 0);
+		window.rect = mu_rect(370, 40, 340, 200);
+	}
 
-  if (mu_begin_window(ctx, &window, "Log Window")) {
-    int widths[] = { -1, -1 };
+	if (mu_begin_window(ctx, &window, "Log Window")) {
+		int widths[] = { -1, -1 };
 
-    /* output text panel */
-    static mu_Container panel;
-    mu_layout_row(ctx, 1, widths, -28);
-    mu_begin_panel(ctx, &panel);
-    mu_layout_row(ctx, 1, widths, -1);
-    mu_text(ctx, logbuf);
-    mu_end_panel(ctx);
-    if (logbuf_updated) {
-      panel.scroll.y = panel.content_size.y;
-      logbuf_updated = 0;
-    }
+		/* output text panel */
+		static mu_Container panel;
+		mu_layout_row(ctx, 1, widths, -28);
+		mu_begin_panel(ctx, &panel);
+		mu_layout_row(ctx, 1, widths, -1);
+		mu_text(ctx, logbuf);
+		mu_end_panel(ctx);
+		if (logbuf_updated) {
+			panel.scroll.y = panel.content_size.y;
+			logbuf_updated = 0;
+		}
 
-    /* input textbox + submit button */
-    static char buf[128];
-    int submitted = 0;
-    widths[0] = -text_width("Submit")-8;
-    mu_layout_row(ctx, 2, widths, -1);
-    if (mu_textbox(ctx, buf, sizeof(buf)) & MU_RES_SUBMIT) {
-      mu_set_focus(ctx, ctx->last_id);
-      submitted = 1;
-    }
-    if (mu_button(ctx, "Submit")) { submitted = 1; }
-    if (submitted) {
-      write_log(buf);
-      buf[0] = '\0';
-    }
+		/* input textbox + submit button */
+		static char buf[128];
+		int submitted = 0;
+		widths[0] = -text_width("Submit")-8;
+		mu_layout_row(ctx, 2, widths, -1);
+		if (mu_textbox(ctx, buf, sizeof(buf)) & MU_RES_SUBMIT) {
+			mu_set_focus(ctx, ctx->last_id);
+			submitted = 1;
+		}
+		if (mu_button(ctx, "Submit")) { submitted = 1; }
+		if (submitted) {
+			write_log(buf);
+			buf[0] = '\0';
+		}
 
-    mu_end_window(ctx);
-  }
+		mu_end_window(ctx);
+	}
 }
 
 
-static int uint8_slider(mu_Context *ctx, unsigned char *value, int low, int high) {
-  static float tmp;
-  mu_push_id(ctx, &value, sizeof(value));
-  tmp = *value;
-  int res = mu_slider_ex(ctx, &tmp, low, high, 0, "%.0f", MU_OPT_ALIGNCENTER);
-  *value = tmp;
-  mu_pop_id(ctx);
-  return res;
+static int
+uint8_slider(mu_Context *ctx, unsigned char *value, int low, int high)
+{
+	static float tmp;
+	mu_push_id(ctx, &value, sizeof(value));
+	tmp = *value;
+	int res = mu_slider_ex(ctx, &tmp, low, high, 0, "%.0f", MU_OPT_ALIGNCENTER);
+	*value = tmp;
+	mu_pop_id(ctx);
+	return res;
 }
 
-static void style_window(mu_Context *ctx) {
-  static mu_Container window;
-  static u8int cur[MU_COLOR_MAX][4], old[MU_COLOR_MAX][4];
-  static struct { const char *label; int idx; } colors[] = {
-    { "background:",   MU_COLOR_BG          },
-    { "text:",         MU_COLOR_TEXT        },
-    { "border:",       MU_COLOR_BORDER      },
-    { "windowbg:",     MU_COLOR_WINDOWBG    },
-    { "titlebg:",      MU_COLOR_TITLEBG     },
-    { "titletext:",    MU_COLOR_TITLETEXT   },
-    { "panelbg:",      MU_COLOR_PANELBG     },
-    { "button:",       MU_COLOR_BUTTON      },
-    { "buttonhover:",  MU_COLOR_BUTTONHOVER },
-    { "buttonfocus:",  MU_COLOR_BUTTONFOCUS },
-    { "base:",         MU_COLOR_BASE        },
-    { "basehover:",    MU_COLOR_BASEHOVER   },
-    { "basefocus:",    MU_COLOR_BASEFOCUS   },
-    { "scrollbase:",   MU_COLOR_SCROLLBASE  },
-    { "scrollthumb:",  MU_COLOR_SCROLLTHUMB },
-    { nil }
-  };
+static void
+style_window(mu_Context *ctx)
+{
+	static mu_Container window;
+	static u8int cur[MU_COLOR_MAX][4], old[MU_COLOR_MAX][4];
+	static struct { const char *label; int idx; } colors[] = {
+		{ "background:", MU_COLOR_BG },
+		{ "text:", MU_COLOR_TEXT },
+		{ "border:", MU_COLOR_BORDER },
+		{ "windowbg:", MU_COLOR_WINDOWBG },
+		{ "titlebg:", MU_COLOR_TITLEBG },
+		{ "titletext:", MU_COLOR_TITLETEXT },
+		{ "panelbg:", MU_COLOR_PANELBG },
+		{ "button:", MU_COLOR_BUTTON },
+		{ "buttonhover:", MU_COLOR_BUTTONHOVER },
+		{ "buttonfocus:", MU_COLOR_BUTTONFOCUS },
+		{ "base:", MU_COLOR_BASE },
+		{ "basehover:", MU_COLOR_BASEHOVER },
+		{ "basefocus:", MU_COLOR_BASEFOCUS },
+		{ "scrollbase:", MU_COLOR_SCROLLBASE },
+		{ "scrollthumb:", MU_COLOR_SCROLLTHUMB },
+		{ nil }
+	};
 
-  /* init window manually so we can set its position and size */
-  if (!window.inited) {
-    mu_init_window(ctx, &window, 0);
-    window.rect = mu_rect(370, 250, 340, 290);
-    memmove(cur, defaultcolors, sizeof(cur));
-    memmove(old, defaultcolors, sizeof(old));
-  }
+	/* init window manually so we can set its position and size */
+	if (!window.inited) {
+		mu_init_window(ctx, &window, 0);
+		window.rect = mu_rect(370, 250, 340, 290);
+		memmove(cur, defaultcolors, sizeof(cur));
+		memmove(old, defaultcolors, sizeof(old));
+	}
 
-  if (mu_begin_window(ctx, &window, "Style Editor")) {
-    int sw = mu_max(text_width("255"), mu_get_container(ctx)->body.w * 0.14);
-    const int widths[] = { text_width("scrollthumb:"), sw, sw, sw, sw, -1 };
-    mu_layout_row(ctx, 6, widths, 0);
-    for (int i = 0; colors[i].label; i++) {
-      mu_label(ctx, colors[i].label);
-      uint8_slider(ctx, &cur[i][0], 0, 255);
-      uint8_slider(ctx, &cur[i][1], 0, 255);
-      uint8_slider(ctx, &cur[i][2], 0, 255);
-      uint8_slider(ctx, &cur[i][3], 0, 255);
-      if (memcmp(cur[i], old[i], 4) != 0) {
-        freeimage(ctx->style->colors[i]);
-        ctx->style->colors[i] = mu_color(cur[i][0], cur[i][1], cur[i][2], cur[i][3]);
-        memmove(old[i], cur[i], 4);
-      }
-      mu_draw_rect(ctx, mu_layout_next(ctx), ctx->style->colors[i]);
-    }
-    mu_end_window(ctx);
-  }
+	if (mu_begin_window(ctx, &window, "Style Editor")) {
+		int sw = max(text_width("255"), mu_get_container(ctx)->body.w * 0.14);
+		const int widths[] = { text_width("scrollthumb:"), sw, sw, sw, sw, -1 };
+		mu_layout_row(ctx, 6, widths, 0);
+		for (int i = 0; colors[i].label; i++) {
+			mu_label(ctx, colors[i].label);
+			uint8_slider(ctx, &cur[i][0], 0, 255);
+			uint8_slider(ctx, &cur[i][1], 0, 255);
+			uint8_slider(ctx, &cur[i][2], 0, 255);
+			uint8_slider(ctx, &cur[i][3], 0, 255);
+			if (memcmp(cur[i], old[i], 4) != 0) {
+				freeimage(ctx->style->colors[i]);
+				ctx->style->colors[i] = mu_color(cur[i][0], cur[i][1], cur[i][2], cur[i][3]);
+				memmove(old[i], cur[i], 4);
+			}
+			mu_draw_rect(ctx, mu_layout_next(ctx), ctx->style->colors[i]);
+		}
+		mu_end_window(ctx);
+	}
 }
 
-void process_frame(mu_Context *ctx) {
-  mu_begin(ctx);
-  test_window(ctx);
-  log_window(ctx);
-  style_window(ctx);
-  mu_end(ctx);
+void
+process_frame(mu_Context *ctx)
+{
+	mu_begin(ctx);
+	test_window(ctx);
+	log_window(ctx);
+	style_window(ctx);
+	mu_end(ctx);
 }
binary files /dev/null b/icons/mu_icon_resize.png differ
--- a/microui.c
+++ b/microui.c
@@ -3,39 +3,22 @@
 #include <draw.h>
 #include "microui.h"
 
-#define expect(x) do { \
-    if (!(x)) { \
-      fprint(2, "Fatal error: %s:%d: assertion '%s' failed\n", __FILE__, __LINE__, #x); \
-      abort(); \
-    } \
-  } while (0)
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+#define clamp(x, a, b) min(b, max(a, x))
 
-
-#define push(stk, val) do { \
-    expect((stk).idx < (int) (sizeof((stk).items) / sizeof(*(stk).items))); \
-    (stk).items[ (stk).idx ] = (val); \
-    (stk).idx++; \
-  } while (0)
-
-
-#define pop(stk) do { \
-    expect((stk).idx > 0); \
-    (stk).idx--; \
-  } while (0)
-
-
 static mu_Rect unclipped_rect = { 0, 0, 0x1000000, 0x1000000 };
 
 static mu_Style default_style = {
-  .font = nil,
-  .size = { 68, 10 },
-  .padding = 6,
-  .spacing = 4,
-  .indent = 24,
-  .title_height = 26,
-  .scrollbar_size = 12,
-  .thumb_size = 8,
-  .colors = {nil},
+	.font = nil,
+	.size = { 68, 10 },
+	.padding = 6,
+	.spacing = 4,
+	.indent = 24,
+	.title_height = 26,
+	.scrollbar_size = 12,
+	.thumb_size = 8,
+	.colors = {nil},
 };
 
 static u8int atlasraw[] = {
@@ -42,42 +25,46 @@
 	0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x72, 0x38,
 	0x67, 0x38, 0x62, 0x38, 0x61, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
 	0x20, 0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x20, 0x20,
-	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x36, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-	0x20, 0x20, 0x20, 0x20, 0x31, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
-	0x31, 0x38, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x38, 0x36, 0x20, 0x80,
-	0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x8f, 0x00,
-	0x00, 0x74, 0x13, 0x04, 0x0f, 0x04, 0x17, 0x7c, 0x51, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x14,
-	0x8f, 0x24, 0xa7, 0x34, 0x13, 0x24, 0x0f, 0x7c, 0x51, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c,
-	0xbb, 0x2c, 0x1b, 0x7c, 0x00, 0x7c, 0x00, 0x34, 0x00, 0x80, 0x14, 0x00, 0x00, 0x80, 0x5c, 0x00,
-	0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x7c, 0xbb, 0x5c, 0x13, 0x7c, 0x00, 0x3c, 0x00, 0x80,
-	0x20, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0x04, 0x07, 0x44, 0x1f, 0x80, 0x5e, 0x00, 0x00, 0x04,
-	0x67, 0x80, 0x70, 0x00, 0x00, 0x34, 0x1b, 0x04, 0x13, 0x04, 0x1b, 0x04, 0x23, 0x7c, 0xb3, 0x2c,
-	0x1b, 0x24, 0x0f, 0x7c, 0x00, 0x2c, 0x00, 0x80, 0x21, 0x00, 0x00, 0x80, 0xe0, 0x00, 0x00, 0x80,
-	0xea, 0x00, 0x00, 0x80, 0x2c, 0x00, 0x00, 0x54, 0x27, 0x14, 0x9f, 0x24, 0xbb, 0x44, 0x13, 0x7c,
-	0xb3, 0x4c, 0x00, 0x7c, 0x00, 0x4c, 0xb3, 0x80, 0x2d, 0x00, 0x00, 0x74, 0x2f, 0x24, 0xa7, 0x64,
-	0xb3, 0x04, 0x00, 0x7c, 0xb3, 0x2c, 0x00, 0x7c, 0x00, 0x1c, 0xb3, 0x80, 0xe1, 0x00, 0x00, 0x80,
-	0xeb, 0x00, 0x00, 0x7c, 0xb3, 0x3c, 0xbb, 0x64, 0xb3, 0x7c, 0x00, 0x3c, 0x00, 0x24, 0x00, 0x80,
-	0x0e, 0x00, 0x00, 0x7c, 0xb3, 0x7c, 0xb3, 0x7c, 0xb7, 0x7c, 0x00, 0x74, 0x00, 0x14, 0x00, 0x80,
-	0x3d, 0x00, 0x00, 0x80, 0xed, 0x00, 0x00, 0x80, 0x45, 0x00, 0x00, 0x24, 0x17, 0x80, 0x22, 0x00,
-	0x00, 0x7c, 0xb3, 0x7e, 0x27, 0x76, 0x27, 0x7c, 0x00, 0x2c, 0x00, 0x14, 0x00, 0x80, 0x13, 0x00,
-	0x00, 0x80, 0xd0, 0x00, 0x00, 0x80, 0xf6, 0x00, 0x00, 0x14, 0xbb, 0x24, 0xb3, 0x80, 0x2e, 0x00,
-	0x00, 0x7c, 0x45, 0x7f, 0x97, 0x7c, 0xbb, 0x7c, 0x00, 0x04, 0x00, 0x54, 0xbb, 0x80, 0x63, 0x00,
-	0x00, 0x7c, 0xb3, 0x4c, 0x00, 0x80, 0x5e, 0x00, 0x00, 0x54, 0x9f, 0x14, 0xbb, 0x04, 0x23, 0x7c,
-	0x49, 0x5c, 0x00, 0x54, 0xbb, 0x04, 0x5b, 0x80, 0xec, 0x00, 0x00, 0x7c, 0xb3, 0x3c, 0x00, 0x80,
-	0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x7c, 0x49, 0x5c,
-	0x00, 0x54, 0xbb, 0x80, 0xbc, 0x00, 0x00, 0x7c, 0xb3, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x44,
-	0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x2c, 0x00, 0x7c, 0x00, 0x7c,
-	0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x2c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c,
-	0x00, 0x7c, 0x00, 0x2c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x2c,
-	0x00,
+	0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x34, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x20, 0x20, 0x20, 0x20, 0x32, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x32, 0x35, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x34, 0x33, 0x39, 0x20, 0x80,
+	0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x78, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c,
+	0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x34, 0x00, 0x80,
+	0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x24, 0x13, 0x7c,
+	0x00, 0x3c, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, 0xc0, 0x00, 0x00, 0x04, 0x07, 0x44, 0x1f, 0x80,
+	0x5e, 0x00, 0x00, 0x80, 0xff, 0x00, 0x00, 0x80, 0x70, 0x00, 0x00, 0x34, 0x1b, 0x04, 0x13, 0x04,
+	0x1b, 0x04, 0x23, 0x24, 0x17, 0x7c, 0x00, 0x2c, 0x00, 0x80, 0x21, 0x00, 0x00, 0x80, 0xe0, 0x00,
+	0x00, 0x80, 0xea, 0x00, 0x00, 0x80, 0x2c, 0x00, 0x00, 0x54, 0x27, 0x14, 0x6f, 0x24, 0x8b, 0x44,
+	0x13, 0x14, 0x00, 0x7c, 0x00, 0x4c, 0x83, 0x80, 0x2d, 0x00, 0x00, 0x74, 0x2f, 0x24, 0x77, 0x74,
+	0x83, 0x7c, 0x00, 0x1c, 0x83, 0x80, 0xe1, 0x00, 0x00, 0x80, 0xeb, 0x00, 0x00, 0x7c, 0x83, 0x3c,
+	0x8b, 0x74, 0x83, 0x24, 0x00, 0x80, 0x0e, 0x00, 0x00, 0x7c, 0x83, 0x7c, 0x83, 0x7c, 0x87, 0x3c,
+	0x00, 0x14, 0x00, 0x80, 0x3d, 0x00, 0x00, 0x80, 0xed, 0x00, 0x00, 0x80, 0x45, 0x00, 0x00, 0x24,
+	0x17, 0x80, 0x22, 0x00, 0x00, 0x7c, 0x83, 0x7d, 0x97, 0x75, 0x97, 0x14, 0x00, 0x80, 0x13, 0x00,
+	0x00, 0x80, 0xd0, 0x00, 0x00, 0x80, 0xf6, 0x00, 0x00, 0x14, 0x8b, 0x24, 0x83, 0x80, 0x2e, 0x00,
+	0x00, 0x7c, 0x79, 0x7e, 0xa7, 0x54, 0x8b, 0x54, 0x8b, 0x80, 0x63, 0x00, 0x00, 0x7c, 0x83, 0x4c,
+	0x00, 0x7f, 0xb7, 0x3f, 0xb7, 0x54, 0x8b, 0x04, 0x2b, 0x80, 0xec, 0x00, 0x00, 0x7c, 0x83, 0x3c,
+	0x00, 0x80, 0x14, 0x00, 0x00, 0x80, 0x5c, 0x00, 0x00, 0x54, 0x1f, 0x04, 0x1b, 0x04, 0x23, 0x24,
+	0x13, 0x54, 0x8b, 0x80, 0xbc, 0x00, 0x00, 0x7c, 0x83, 0x7c, 0x00, 0x7c, 0x00, 0x0c, 0x00, 0x7c,
+	0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x00, 0x7c,
+	0x00, 0x7c, 0x00, 0x64, 0x00, 0x80, 0x5a, 0x00, 0x00, 0x06, 0x6b, 0x14, 0x07, 0x80, 0x8f, 0x00,
+	0x00, 0x44, 0x27, 0x7c, 0x00, 0x7c, 0x00, 0x64, 0x00, 0x80, 0x3c, 0x00, 0x00, 0x80, 0xaa, 0x00,
+	0x00, 0x04, 0x07, 0x04, 0x83, 0x54, 0x8b, 0x44, 0x17, 0x14, 0x2f, 0x7c, 0x65, 0x7c, 0x00, 0x34,
+	0x00, 0x54, 0x8b, 0x34, 0x17, 0x64, 0xb3, 0x7c, 0x00, 0x0c, 0x00, 0x80, 0x6e, 0x00, 0x00, 0x05,
+	0x03, 0x35, 0x0f, 0x64, 0x8b, 0x34, 0x17, 0x7c, 0x83, 0x7c, 0x00, 0x80, 0xa5, 0x00, 0x00, 0x15,
+	0x4f, 0x26, 0x1f, 0x64, 0x83, 0x74, 0xa3, 0x7c, 0x00, 0x7c, 0x00, 0x7c, 0x63, 0x81, 0x00, 0x00,
+	0x34, 0x27, 0x7c, 0x4d, 0x4c, 0x00, 0x80, 0x55, 0x00, 0x00, 0x80, 0x37, 0x00, 0x00, 0x04, 0x0b,
+	0x04, 0x07, 0x04, 0x0f, 0x04, 0x0b, 0x80, 0x1e, 0x00, 0x00, 0x04, 0x0b, 0x04, 0x07, 0x64, 0x83,
+	0x7c, 0x00, 0x7c, 0x00, 0x16, 0xef, 0x05, 0x8f, 0x75, 0x97, 0x54, 0x00, 0x7c, 0x00, 0x7c, 0x00,
+	0x7d, 0x0f, 0x0d, 0x0f, 0x64, 0x3f,
 };
 
 static mu_Rect default_atlas_icons[] = {
 	[MU_ICON_CHECK] = {0, 0, 18, 18},
 	[MU_ICON_CLOSE] = {18, 0, 16, 16},
-	[MU_ICON_COLLAPSED] = {34, 0, 5, 7},
-	[MU_ICON_EXPANDED] = {39, 0, 7, 5},
-	[ATLAS_DIMENSIONS] = {0, 0, 46, 18},
+	[MU_ICON_COLLAPSED] = {27, 16, 5, 7},
+	[MU_ICON_EXPANDED] = {0, 18, 7, 5},
+	[MU_ICON_RESIZE] = {18, 16, 9, 9},
+	[ATLAS_DIMENSIONS] = {0, 0, 34, 25},
 };
 
 Image *atlasimage = nil;
@@ -100,12 +87,24 @@
 	[MU_COLOR_SCROLLTHUMB] = {30, 30, 30, 255},
 };
 
-mu_Rect mu_rect(int x, int y, int w, int h) {
-  mu_Rect res;
-  res.x = x, res.y = y, res.w = w, res.h = h;
-  return res;
+static void
+buffer_grow(void **buf, int onesz, int *bufmax, int bufnum)
+{
+	while (*bufmax <= bufnum) {
+		*bufmax = max(16, *bufmax) * 2;
+		if ((*buf = realloc(*buf, *bufmax*onesz)) == nil)
+			sysfatal("not enough memory for %d items (%d bytes)", *bufmax, *bufmax*onesz);
+	}
 }
 
+mu_Rect
+mu_rect(int x, int y, int w, int h)
+{
+	mu_Rect res;
+	res.x = x, res.y = y, res.w = w, res.h = h;
+	return res;
+}
+
 Image *
 mu_color(u8int r, u8int g, u8int b, u8int a)
 {
@@ -128,35 +127,40 @@
 	return rect;
 }
 
-static mu_Rect expand_rect(mu_Rect rect, int n) {
-  return mu_rect(rect.x - n, rect.y - n, rect.w + n * 2, rect.h + n * 2);
+static mu_Rect
+expand_rect(mu_Rect rect, int n) {
+	return mu_rect(rect.x - n, rect.y - n, rect.w + n * 2, rect.h + n * 2);
 }
 
 
-static mu_Rect clip_rect(mu_Rect r1, mu_Rect r2) {
-  int x1 = mu_max(r1.x, r2.x);
-  int y1 = mu_max(r1.y, r2.y);
-  int x2 = mu_min(r1.x + r1.w, r2.x + r2.w);
-  int y2 = mu_min(r1.y + r1.h, r2.y + r2.h);
-  if (x2 < x1) { x2 = x1; }
-  if (y2 < y1) { y2 = y1; }
-  return mu_rect(x1, y1, x2 - x1, y2 - y1);
+static mu_Rect
+clip_rect(mu_Rect r1, mu_Rect r2)
+{
+	int x1 = max(r1.x, r2.x);
+	int y1 = max(r1.y, r2.y);
+	int x2 = min(r1.x + r1.w, r2.x + r2.w);
+	int y2 = min(r1.y + r1.h, r2.y + r2.h);
+	if (x2 < x1) { x2 = x1; }
+	if (y2 < y1) { y2 = y1; }
+	return mu_rect(x1, y1, x2 - x1, y2 - y1);
 }
 
 
-static int rect_overlaps_vec2(mu_Rect r, Point p) {
-  return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h;
+static int
+rect_overlaps_vec2(mu_Rect r, Point p)
+{
+	return p.x >= r.x && p.x < r.x + r.w && p.y >= r.y && p.y < r.y + r.h;
 }
 
 static void
 draw_frame(mu_Context *ctx, mu_Rect rect, int colorid)
 {
-  mu_draw_rect(ctx, rect, ctx->style->colors[colorid]);
-  if (colorid == MU_COLOR_SCROLLBASE  ||
-      colorid == MU_COLOR_SCROLLTHUMB ||
-      colorid == MU_COLOR_TITLEBG) { return; }
-  /* draw border */
-  mu_draw_box(ctx, expand_rect(rect, 1), ctx->style->colors[MU_COLOR_BORDER]);
+	mu_draw_rect(ctx, rect, ctx->style->colors[colorid]);
+	if (colorid == MU_COLOR_SCROLLBASE	||
+			colorid == MU_COLOR_SCROLLTHUMB ||
+			colorid == MU_COLOR_TITLEBG) { return; }
+	/* draw border */
+	mu_draw_box(ctx, expand_rect(rect, 1), ctx->style->colors[MU_COLOR_BORDER]);
 }
 
 static int
@@ -198,192 +202,221 @@
 	ctx->style = &ctx->_style;
 }
 
-void mu_begin(mu_Context *ctx) {
-  ctx->command_list.idx = 0;
-  ctx->root_list.idx = 0;
-  ctx->scroll_target = nil;
-  ctx->last_hover_root = ctx->hover_root;
-  ctx->hover_root = nil;
-  ctx->mouse_delta.x = ctx->mouse_pos.x - ctx->last_mouse_pos.x;
-  ctx->mouse_delta.y = ctx->mouse_pos.y - ctx->last_mouse_pos.y;
+void
+mu_begin(mu_Context *ctx)
+{
+	ctx->cmdsnum = ctx->rootnum = 0;
+	ctx->strnum = 0;
+	ctx->scroll_target = nil;
+	ctx->last_hover_root = ctx->hover_root;
+	ctx->hover_root = nil;
+	ctx->mouse_delta.x = ctx->mouse_pos.x - ctx->last_mouse_pos.x;
+	ctx->mouse_delta.y = ctx->mouse_pos.y - ctx->last_mouse_pos.y;
 }
 
-
-static int compare_zindex(const void *a, const void *b) {
-  return (*(mu_Container**) a)->zindex - (*(mu_Container**) b)->zindex;
+static int
+compare_zindex(const void *a, const void *b)
+{
+	return (*(mu_Container**) a)->zindex - (*(mu_Container**) b)->zindex;
 }
 
+void
+mu_end(mu_Context *ctx)
+{
+	int i, n;
+	/* check stacks */
+	assert(ctx->cntnum == 0);
+	assert(ctx->clipnum == 0);
+	assert(ctx->idsnum == 0);
+	assert(ctx->layoutsnum == 0);
 
-void mu_end(mu_Context *ctx) {
-  int i, n;
-  /* check stacks */
-  expect(ctx->container_stack.idx == 0);
-  expect(ctx->clip_stack.idx      == 0);
-  expect(ctx->id_stack.idx        == 0);
-  expect(ctx->layout_stack.idx    == 0);
+	/* handle scroll input */
+	if (ctx->scroll_target) {
+		ctx->scroll_target->scroll.x += ctx->scroll_delta.x;
+		ctx->scroll_target->scroll.y += ctx->scroll_delta.y;
+	}
 
-  /* handle scroll input */
-  if (ctx->scroll_target) {
-    ctx->scroll_target->scroll.x += ctx->scroll_delta.x;
-    ctx->scroll_target->scroll.y += ctx->scroll_delta.y;
-  }
+	/* unset focus if focus id was not touched this frame */
+	if (!ctx->updated_focus) { ctx->focus = 0; }
+	ctx->updated_focus = 0;
 
-  /* unset focus if focus id was not touched this frame */
-  if (!ctx->updated_focus) { ctx->focus = 0; }
-  ctx->updated_focus = 0;
+	/* bring hover root to front if mouse was pressed */
+	if (ctx->mouse_pressed && ctx->hover_root && ctx->hover_root->zindex < ctx->last_zindex)
+		mu_bring_to_front(ctx, ctx->hover_root);
 
-  /* bring hover root to front if mouse was pressed */
-  if (ctx->mouse_pressed && ctx->hover_root &&
-      ctx->hover_root->zindex < ctx->last_zindex)
-  {
-    mu_bring_to_front(ctx, ctx->hover_root);
-  }
+	/* reset input state */
+	ctx->key_pressed = 0;
+	ctx->text_input[0] = 0;
+	ctx->mouse_pressed = 0;
+	ctx->scroll_delta = ZP;
+	ctx->last_mouse_pos = ctx->mouse_pos;
 
-  /* reset input state */
-  ctx->key_pressed = 0;
-  ctx->text_input[0] = '\0';
-  ctx->mouse_pressed = 0;
-  ctx->scroll_delta = ZP;
-  ctx->last_mouse_pos = ctx->mouse_pos;
+	/* sort root containers by zindex */
+	n = ctx->rootnum;
+	qsort(ctx->root, n, sizeof(*ctx->root), compare_zindex);
 
-  /* sort root containers by zindex */
-  n = ctx->root_list.idx;
-  qsort(ctx->root_list.items, n, sizeof(mu_Container*), compare_zindex);
+	/* set root container jump commands */
+	for (i = 0; i < n; i++) {
+		mu_Container *cnt = ctx->root[i];
+		/* if this is the first container then make the first command jump to it.
+		** otherwise set the previous container's tail to jump to this one */
+		if (i == 0)
+			ctx->cmds[0].jump.dst = cnt->head + 1;
+		else
+			ctx->cmds[ctx->root[i - 1]->tail].jump.dst = cnt->head + 1;
 
-  /* set root container jump commands */
-  for (i = 0; i < n; i++) {
-    mu_Container *cnt = ctx->root_list.items[i];
-    /* if this is the first container then make the first command jump to it.
-    ** otherwise set the previous container's tail to jump to this one */
-    if (i == 0) {
-      mu_Command *cmd = (mu_Command*) ctx->command_list.items;
-      cmd->jump.dst = (char*) cnt->head + sizeof(mu_JumpCommand);
-    } else {
-      mu_Container *prev = ctx->root_list.items[i - 1];
-      prev->tail->jump.dst = (char*) cnt->head + sizeof(mu_JumpCommand);
-    }
-    /* make the last container's tail jump to the end of command list */
-    if (i == n - 1) {
-      cnt->tail->jump.dst = ctx->command_list.items + ctx->command_list.idx;
-    }
-  }
+		/* make the last container's tail jump to the end of command list */
+		if (i == n - 1)
+			ctx->cmds[cnt->tail].jump.dst = ctx->cmdsnum;
+	}
 }
 
 
-void mu_set_focus(mu_Context *ctx, mu_Id id) {
-  ctx->focus = id;
-  ctx->updated_focus = 1;
+void
+mu_set_focus(mu_Context *ctx, mu_Id id)
+{
+	ctx->focus = id;
+	ctx->updated_focus = 1;
 }
 
-
 /* 32bit fnv-1a hash */
 #define HASH_INITIAL 2166136261
 
-static void hash(mu_Id *hash, const void *data, int size) {
-  const unsigned char *p = data;
-  while (size--) {
-    *hash = (*hash ^ *p++) * 16777619;
-  }
+static void
+hash(mu_Id *hash, const void *data, int size)
+{
+	const unsigned char *p = data;
+	while (size--) {
+		*hash = (*hash ^ *p++) * 16777619;
+	}
 }
 
 
-mu_Id mu_get_id(mu_Context *ctx, const void *data, int size) {
-  int idx = ctx->id_stack.idx;
-  mu_Id res = (idx > 0) ? ctx->id_stack.items[idx - 1] : HASH_INITIAL;
-  hash(&res, data, size);
-  ctx->last_id = res;
-  return res;
+mu_Id
+mu_get_id(mu_Context *ctx, const void *data, int size)
+{
+	int idx = ctx->idsnum;
+	mu_Id res = (idx > 0) ? ctx->ids[idx - 1] : HASH_INITIAL;
+	hash(&res, data, size);
+	ctx->last_id = res;
+	return res;
 }
 
 
-void mu_push_id(mu_Context *ctx, const void *data, int size) {
-  push(ctx->id_stack, mu_get_id(ctx, data, size));
+void
+mu_push_id(mu_Context *ctx, const void *data, int size)
+{
+	buffer_grow(&ctx->ids, sizeof(*ctx->ids), &ctx->idsmax, ctx->idsnum);
+	ctx->ids[ctx->idsnum++] = mu_get_id(ctx, data, size);
 }
 
-
-void mu_pop_id(mu_Context *ctx) {
-  pop(ctx->id_stack);
+void
+mu_pop_id(mu_Context *ctx)
+{
+	ctx->idsnum--;
 }
 
-
-void mu_push_clip_rect(mu_Context *ctx, mu_Rect rect) {
-  mu_Rect last = mu_get_clip_rect(ctx);
-  push(ctx->clip_stack, clip_rect(rect, last));
+void
+mu_push_clip_rect(mu_Context *ctx, mu_Rect rect)
+{
+	mu_Rect last = mu_get_clip_rect(ctx);
+	buffer_grow(&ctx->clip, sizeof(*ctx->clip), &ctx->clipmax, ctx->clipnum);
+	ctx->clip[ctx->clipnum++] = clip_rect(rect, last);
 }
 
 
-void mu_pop_clip_rect(mu_Context *ctx) {
-  pop(ctx->clip_stack);
+void
+mu_pop_clip_rect(mu_Context *ctx)
+{
+	ctx->clipnum--;
 }
 
 
-mu_Rect mu_get_clip_rect(mu_Context *ctx) {
-  expect(ctx->clip_stack.idx > 0);
-  return ctx->clip_stack.items[ ctx->clip_stack.idx - 1 ];
+mu_Rect
+mu_get_clip_rect(mu_Context *ctx)
+{
+	assert(ctx->clipnum > 0);
+	return ctx->clip[ctx->clipnum - 1];
 }
 
 
-int mu_check_clip(mu_Context *ctx, mu_Rect r) {
-  mu_Rect cr = mu_get_clip_rect(ctx);
-  if (r.x > cr.x + cr.w || r.x + r.w < cr.x ||
-      r.y > cr.y + cr.h || r.y + r.h < cr.y    ) { return MU_CLIP_ALL;  }
-  if (r.x >= cr.x && r.x + r.w <= cr.x + cr.w &&
-      r.y >= cr.y && r.y + r.h <= cr.y + cr.h  ) { return MU_CLIP_NONE; }
-  return MU_CLIP_PART;
+int
+mu_check_clip(mu_Context *ctx, mu_Rect r)
+{
+	mu_Rect cr = mu_get_clip_rect(ctx);
+	if (r.x > cr.x + cr.w || r.x + r.w < cr.x || r.y > cr.y + cr.h || r.y + r.h < cr.y)
+		return MU_CLIP_ALL;
+	if (r.x >= cr.x && r.x + r.w <= cr.x + cr.w && r.y >= cr.y && r.y + r.h <= cr.y + cr.h)
+		return MU_CLIP_NONE;
+	return MU_CLIP_PART;
 }
 
 
-static void push_layout(mu_Context *ctx, mu_Rect body, Point scroll) {
-  mu_Layout layout;
-  int width = 0;
-  memset(&layout, 0, sizeof(mu_Layout));
-  layout.body = mu_rect(body.x - scroll.x, body.y - scroll.y, body.w, body.h);
-  layout.max = Pt(-0x1000000, -0x1000000);
-  push(ctx->layout_stack, layout);
-  mu_layout_row(ctx, 1, &width, 0);
+static void
+push_layout(mu_Context *ctx, mu_Rect body, Point scroll)
+{
+	mu_Layout layout;
+	int width = 0;
+	memset(&layout, 0, sizeof(mu_Layout));
+	layout.body = mu_rect(body.x - scroll.x, body.y - scroll.y, body.w, body.h);
+	layout.max = Pt(-0x1000000, -0x1000000);
+	buffer_grow(&ctx->layouts, sizeof(*ctx->layouts), &ctx->layoutsmax, ctx->layoutsnum);
+	ctx->layouts[ctx->layoutsnum++] = layout;
+	mu_layout_row(ctx, 1, &width, 0);
 }
 
-
-static mu_Layout* get_layout(mu_Context *ctx) {
-  return &ctx->layout_stack.items[ctx->layout_stack.idx - 1];
+static mu_Layout *
+get_layout(mu_Context *ctx)
+{
+	return &ctx->layouts[ctx->layoutsnum - 1];
 }
 
 
-static void push_container(mu_Context *ctx, mu_Container *cnt) {
-  push(ctx->container_stack, cnt);
-  mu_push_id(ctx, &cnt, sizeof(mu_Container*));
+static void
+push_container(mu_Context *ctx, mu_Container *cnt)
+{
+	buffer_grow(&ctx->cnt, sizeof(*ctx->cnt), &ctx->cntmax, ctx->cntnum);
+	ctx->cnt[ctx->cntnum++] = cnt;
+	mu_push_id(ctx, &cnt, sizeof(mu_Container*));
 }
 
 
-static void pop_container(mu_Context *ctx) {
-  mu_Container *cnt = mu_get_container(ctx);
-  mu_Layout *layout = get_layout(ctx);
-  cnt->content_size.x = layout->max.x - layout->body.x;
-  cnt->content_size.y = layout->max.y - layout->body.y;
-  /* pop container, layout and id */
-  pop(ctx->container_stack);
-  pop(ctx->layout_stack);
-  mu_pop_id(ctx);
+static void
+pop_container(mu_Context *ctx)
+{
+	mu_Container *cnt = mu_get_container(ctx);
+	mu_Layout *layout = get_layout(ctx);
+	cnt->content_size.x = layout->max.x - layout->body.x;
+	cnt->content_size.y = layout->max.y - layout->body.y;
+	ctx->cntnum--;
+	ctx->layoutsnum--;
+	mu_pop_id(ctx);
 }
 
 
-mu_Container* mu_get_container(mu_Context *ctx) {
-  expect(ctx->container_stack.idx > 0);
-  return ctx->container_stack.items[ ctx->container_stack.idx - 1 ];
+mu_Container *
+mu_get_container(mu_Context *ctx)
+{
+	assert(ctx->cntnum > 0);
+	return ctx->cnt[ctx->cntnum - 1];
 }
 
 
-void mu_init_window(mu_Context *ctx, mu_Container *cnt, int opt) {
-  memset(cnt, 0, sizeof(*cnt));
-  cnt->inited = 1;
-  cnt->open = opt & MU_OPT_CLOSED ? 0 : 1;
-  cnt->rect = mu_rect(100, 100, 300, 300);
-  mu_bring_to_front(ctx, cnt);
+void
+mu_init_window(mu_Context *ctx, mu_Container *cnt, int opt)
+{
+	memset(cnt, 0, sizeof(*cnt));
+	cnt->inited = 1;
+	cnt->open = opt & MU_OPT_CLOSED ? 0 : 1;
+	cnt->rect = mu_rect(100, 100, 300, 300);
+	mu_bring_to_front(ctx, cnt);
 }
 
 
-void mu_bring_to_front(mu_Context *ctx, mu_Container *cnt) {
-  cnt->zindex = ++ctx->last_zindex;
+void
+mu_bring_to_front(mu_Context *ctx, mu_Container *cnt)
+{
+	cnt->zindex = ++ctx->last_zindex;
 }
 
 
@@ -391,46 +424,60 @@
 ** input handlers
 **============================================================================*/
 
-void mu_input_mousemove(mu_Context *ctx, int x, int y) {
-  ctx->mouse_pos = Pt(x, y);
+void
+mu_input_mousemove(mu_Context *ctx, int x, int y)
+{
+	ctx->mouse_pos = Pt(x, y);
 }
 
 
-void mu_input_mousedown(mu_Context *ctx, int x, int y, int btn) {
-  mu_input_mousemove(ctx, x, y);
-  ctx->mouse_down |= btn;
-  ctx->mouse_pressed |= btn;
+void
+mu_input_mousedown(mu_Context *ctx, int x, int y, int btn)
+{
+	mu_input_mousemove(ctx, x, y);
+	ctx->mouse_down |= btn;
+	ctx->mouse_pressed |= btn;
 }
 
 
-void mu_input_mouseup(mu_Context *ctx, int x, int y, int btn) {
-  mu_input_mousemove(ctx, x, y);
-  ctx->mouse_down &= ~btn;
+void
+mu_input_mouseup(mu_Context *ctx, int x, int y, int btn)
+{
+	mu_input_mousemove(ctx, x, y);
+	ctx->mouse_down &= ~btn;
 }
 
 
-void mu_input_scroll(mu_Context *ctx, int x, int y) {
-  ctx->scroll_delta.x += x;
-  ctx->scroll_delta.y += y;
+void
+mu_input_scroll(mu_Context *ctx, int x, int y)
+{
+	ctx->scroll_delta.x += x;
+	ctx->scroll_delta.y += y;
 }
 
 
-void mu_input_keydown(mu_Context *ctx, int key) {
-  ctx->key_pressed |= key;
-  ctx->key_down |= key;
+void
+mu_input_keydown(mu_Context *ctx, int key)
+{
+	ctx->key_pressed |= key;
+	ctx->key_down |= key;
 }
 
 
-void mu_input_keyup(mu_Context *ctx, int key) {
-  ctx->key_down &= ~key;
+void
+mu_input_keyup(mu_Context *ctx, int key)
+{
+	ctx->key_down &= ~key;
 }
 
 
-void mu_input_text(mu_Context *ctx, const char *text) {
-  int len = strlen(ctx->text_input);
-  int size = strlen(text) + 1;
-  expect(len + size <= (int) sizeof(ctx->text_input));
-  memcpy(ctx->text_input + len, text, size);
+void
+mu_input_text(mu_Context *ctx, const char *text)
+{
+	int len = strlen(ctx->text_input);
+	int size = strlen(text) + 1;
+	assert(len + size <= (int) sizeof(ctx->text_input));
+	memcpy(ctx->text_input + len, text, size);
 }
 
 /*============================================================================
@@ -437,97 +484,109 @@
 ** commandlist
 **============================================================================*/
 
-mu_Command* mu_push_command(mu_Context *ctx, int type, int size) {
-  mu_Command *cmd = (mu_Command*) (ctx->command_list.items + ctx->command_list.idx);
-  expect(ctx->command_list.idx + size < MU_COMMANDLIST_SIZE);
-  cmd->base.type = type;
-  cmd->base.size = size;
-  ctx->command_list.idx += size;
-  return cmd;
-}
+mu_Command *
+mu_push_command(mu_Context *ctx, int type)
+{
+	mu_Command *cmd;
 
+	buffer_grow(&ctx->cmds, sizeof(mu_Command), &ctx->cmdsmax, ctx->cmdsnum);
+	cmd = &ctx->cmds[ctx->cmdsnum++];
+	memset(cmd, 0, sizeof(*cmd));
+	cmd->type = type;
 
-int mu_next_command(mu_Context *ctx, mu_Command **cmd) {
-  if (*cmd) {
-    *cmd = (mu_Command*) (((char*) *cmd) + (*cmd)->base.size);
-  } else {
-    *cmd = (mu_Command*) ctx->command_list.items;
-  }
-  while ((char*) *cmd != ctx->command_list.items + ctx->command_list.idx) {
-    if ((*cmd)->type != MU_COMMAND_JUMP) { return 1; }
-    *cmd = (*cmd)->jump.dst;
-  }
-  return 0;
+	return cmd;
 }
 
+static int
+push_jump(mu_Context *ctx, int dst)
+{
+	mu_Command *cmd;
+	cmd = mu_push_command(ctx, MU_COMMAND_JUMP);
+	cmd->jump.dst = dst;
+	return ctx->cmdsnum-1;
+}
 
-static mu_Command* push_jump(mu_Context *ctx, mu_Command *dst) {
-  mu_Command *cmd;
-  cmd = mu_push_command(ctx, MU_COMMAND_JUMP, sizeof(mu_JumpCommand));
-  cmd->jump.dst = dst;
-  return cmd;
+void
+mu_set_clip(mu_Context *ctx, mu_Rect rect)
+{
+	mu_Command *cmd;
+	cmd = mu_push_command(ctx, MU_COMMAND_CLIP);
+	cmd->clip.rect = rect;
 }
 
+void
+mu_draw_rect(mu_Context *ctx, mu_Rect rect, Image *color)
+{
+	mu_Command *cmd;
+	rect = clip_rect(rect, mu_get_clip_rect(ctx));
+	if (rect.w > 0 && rect.h > 0) {
+		cmd = mu_push_command(ctx, MU_COMMAND_RECT);
+		cmd->rect.rect = rect;
+		cmd->rect.color = color;
+	}
+}
 
-void mu_set_clip(mu_Context *ctx, mu_Rect rect) {
-  mu_Command *cmd;
-  cmd = mu_push_command(ctx, MU_COMMAND_CLIP, sizeof(mu_ClipCommand));
-  cmd->clip.rect = rect;
+void
+mu_draw_box(mu_Context *ctx, mu_Rect rect, Image *color)
+{
+	mu_draw_rect(ctx, mu_rect(rect.x + 1, rect.y, rect.w - 2, 1), color);
+	mu_draw_rect(ctx, mu_rect(rect.x+1, rect.y + rect.h-1, rect.w-2, 1), color);
+	mu_draw_rect(ctx, mu_rect(rect.x, rect.y, 1, rect.h), color);
+	mu_draw_rect(ctx, mu_rect(rect.x + rect.w - 1, rect.y, 1, rect.h), color);
 }
 
 
-void mu_draw_rect(mu_Context *ctx, mu_Rect rect, Image *color) {
-  mu_Command *cmd;
-  rect = clip_rect(rect, mu_get_clip_rect(ctx));
-  if (rect.w > 0 && rect.h > 0) {
-    cmd = mu_push_command(ctx, MU_COMMAND_RECT, sizeof(mu_RectCommand));
-    cmd->rect.rect = rect;
-    cmd->rect.color = color;
-  }
-}
+void
+mu_draw_text(mu_Context *ctx, Font *font, const char *s, int len, Point pos, Image *color)
+{
+	mu_Command *cmd;
+	mu_Rect rect;
+	int clipped;
 
+	if (len < 0)
+		len = strlen(s);
+	rect = mu_rect(pos.x, pos.y, text_width(font, s, len), font->height);
+	clipped = mu_check_clip(ctx, rect);
 
-void mu_draw_box(mu_Context *ctx, mu_Rect rect, Image *color) {
-  mu_draw_rect(ctx, mu_rect(rect.x + 1, rect.y, rect.w - 2, 1), color);
-  mu_draw_rect(ctx, mu_rect(rect.x+1, rect.y + rect.h-1, rect.w-2, 1), color);
-  mu_draw_rect(ctx, mu_rect(rect.x, rect.y, 1, rect.h), color);
-  mu_draw_rect(ctx, mu_rect(rect.x + rect.w - 1, rect.y, 1, rect.h), color);
-}
+	if (clipped == MU_CLIP_ALL )
+		return;
+	if (clipped == MU_CLIP_PART)
+		mu_set_clip(ctx, mu_get_clip_rect(ctx));
 
+	while (ctx->strmax <= ctx->strnum+len+1) {
+		ctx->strmax = max(ctx->strmax, ctx->strnum+len+1) * 2;
+		if ((ctx->str = realloc(ctx->str, ctx->strmax)) == nil)
+			sysfatal("not enough memory for %d chars", ctx->strmax);
+	}
+	cmd = mu_push_command(ctx, MU_COMMAND_TEXT);
+	cmd->text.s = ctx->strnum;
+	memmove(ctx->str+ctx->strnum, s, len);
+	ctx->strnum += len;
+	ctx->str[ctx->strnum++] = 0;
+	cmd->text.pos = pos;
+	cmd->text.color = color;
+	cmd->text.font = font;
 
-void mu_draw_text(mu_Context *ctx, Font *font, const char *str, int len,
-  Point pos, Image *color)
-{
-  mu_Command *cmd;
-  mu_Rect rect = mu_rect(pos.x, pos.y, text_width(font, str, len), font->height);
-  int clipped = mu_check_clip(ctx, rect);
-  if (clipped == MU_CLIP_ALL ) { return; }
-  if (clipped == MU_CLIP_PART) { mu_set_clip(ctx, mu_get_clip_rect(ctx)); }
-  /* add command */
-  if (len < 0) { len = strlen(str); }
-  cmd = mu_push_command(ctx, MU_COMMAND_TEXT, sizeof(mu_TextCommand) + len);
-  memcpy(cmd->text.str, str, len);
-  cmd->text.str[len] = '\0';
-  cmd->text.pos = pos;
-  cmd->text.color = color;
-  cmd->text.font = font;
-  /* reset clipping if it was set */
-  if (clipped) { mu_set_clip(ctx, unclipped_rect); }
+	/* reset clipping if it was set */
+	if (clipped)
+		mu_set_clip(ctx, unclipped_rect);
 }
 
 
-void mu_draw_icon(mu_Context *ctx, int id, mu_Rect rect) {
-  mu_Command *cmd;
-  /* do clip command if the rect isn't fully contained within the cliprect */
-  int clipped = mu_check_clip(ctx, rect);
-  if (clipped == MU_CLIP_ALL ) { return; }
-  if (clipped == MU_CLIP_PART) { mu_set_clip(ctx, mu_get_clip_rect(ctx)); }
-  /* do icon command */
-  cmd = mu_push_command(ctx, MU_COMMAND_ICON, sizeof(mu_IconCommand));
-  cmd->icon.id = id;
-  cmd->icon.rect = rect;
-  /* reset clipping if it was set */
-  if (clipped) { mu_set_clip(ctx, unclipped_rect); }
+void
+mu_draw_icon(mu_Context *ctx, int id, mu_Rect rect)
+{
+	mu_Command *cmd;
+	/* do clip command if the rect isn't fully contained within the cliprect */
+	int clipped = mu_check_clip(ctx, rect);
+	if (clipped == MU_CLIP_ALL ) { return; }
+	if (clipped == MU_CLIP_PART) { mu_set_clip(ctx, mu_get_clip_rect(ctx)); }
+	/* do icon command */
+	cmd = mu_push_command(ctx, MU_COMMAND_ICON);
+	cmd->icon.id = id;
+	cmd->icon.rect = rect;
+	/* reset clipping if it was set */
+	if (clipped) { mu_set_clip(ctx, unclipped_rect); }
 }
 
 
@@ -535,108 +594,124 @@
 ** layout
 **============================================================================*/
 
-enum { RELATIVE = 1, ABSOLUTE = 2 };
+enum
+{
+	RELATIVE = 1,
+	ABSOLUTE,
+};
 
 
-void mu_layout_begin_column(mu_Context *ctx) {
-  push_layout(ctx, mu_layout_next(ctx), ZP);
+void
+mu_layout_begin_column(mu_Context *ctx)
+{
+	push_layout(ctx, mu_layout_next(ctx), ZP);
 }
 
 
-void mu_layout_end_column(mu_Context *ctx) {
-  mu_Layout *a, *b;
-  b = get_layout(ctx);
-  pop(ctx->layout_stack);
-  /* inherit position/next_row/max from child layout if they are greater */
-  a = get_layout(ctx);
-  a->position.x = mu_max(a->position.x, b->position.x + b->body.x - a->body.x);
-  a->next_row = mu_max(a->next_row, b->next_row + b->body.y - a->body.y);
-  a->max.x = mu_max(a->max.x, b->max.x);
-  a->max.y = mu_max(a->max.y, b->max.y);
+void
+mu_layout_end_column(mu_Context *ctx)
+{
+	mu_Layout *a, *b;
+	b = get_layout(ctx);
+	ctx->layoutsnum--;
+	/* inherit position/next_row/max from child layout if they are greater */
+	a = get_layout(ctx);
+	a->position.x = max(a->position.x, b->position.x + b->body.x - a->body.x);
+	a->next_row = max(a->next_row, b->next_row + b->body.y - a->body.y);
+	a->max.x = max(a->max.x, b->max.x);
+	a->max.y = max(a->max.y, b->max.y);
 }
 
 
-void mu_layout_row(mu_Context *ctx, int items, const int *widths, int height) {
-  mu_Layout *layout = get_layout(ctx);
-  if (widths) {
-    expect(items <= MU_MAX_WIDTHS);
-    memcpy(layout->widths, widths, items * sizeof(widths[0]));
-  }
-  layout->items = items;
-  layout->position = Pt(layout->indent, layout->next_row);
-  layout->size.y = height;
-  layout->row_index = 0;
+void
+mu_layout_row(mu_Context *ctx, int items, const int *widths, int height)
+{
+	mu_Layout *layout = get_layout(ctx);
+	if (widths) {
+		assert(items <= MU_MAX_WIDTHS);
+		memcpy(layout->widths, widths, items * sizeof(widths[0]));
+	}
+	layout->items = items;
+	layout->position = Pt(layout->indent, layout->next_row);
+	layout->size.y = height;
+	layout->row_index = 0;
 }
 
 
-void mu_layout_width(mu_Context *ctx, int width) {
-  get_layout(ctx)->size.x = width;
+void
+mu_layout_width(mu_Context *ctx, int width)
+{
+	get_layout(ctx)->size.x = width;
 }
 
 
-void mu_layout_height(mu_Context *ctx, int height) {
-  get_layout(ctx)->size.y = height;
+void
+mu_layout_height(mu_Context *ctx, int height)
+{
+	get_layout(ctx)->size.y = height;
 }
 
 
-void mu_layout_set_next(mu_Context *ctx, mu_Rect r, int relative) {
-  mu_Layout *layout = get_layout(ctx);
-  layout->next = r;
-  layout->next_type = relative ? RELATIVE : ABSOLUTE;
+void
+mu_layout_set_next(mu_Context *ctx, mu_Rect r, int relative)
+{
+	mu_Layout *layout = get_layout(ctx);
+	layout->next = r;
+	layout->next_type = relative ? RELATIVE : ABSOLUTE;
 }
 
 
-mu_Rect mu_layout_next(mu_Context *ctx) {
-  mu_Layout *layout = get_layout(ctx);
-  mu_Style *style = ctx->style;
-  mu_Rect res;
+mu_Rect
+mu_layout_next(mu_Context *ctx)
+{
+	mu_Layout *layout = get_layout(ctx);
+	mu_Style *style = ctx->style;
+	mu_Rect res;
 
-  if (layout->next_type) {
-    /* handle rect set by `mu_layout_set_next` */
-    int type = layout->next_type;
-    layout->next_type = 0;
-    res = layout->next;
-    if (type == ABSOLUTE) {
-      ctx->last_rect = res;
-      return res;
-    }
+	if (layout->next_type) {
+		/* handle rect set by `mu_layout_set_next` */
+		int type = layout->next_type;
+		layout->next_type = 0;
+		res = layout->next;
+		if (type == ABSOLUTE) {
+			ctx->last_rect = res;
+			return res;
+		}
 
-  } else {
-    /* handle next row */
-    if (layout->row_index == layout->items) {
-      mu_layout_row(ctx, layout->items, nil, layout->size.y);
-    }
+	} else {
+		/* handle next row */
+		if (layout->row_index == layout->items)
+			mu_layout_row(ctx, layout->items, nil, layout->size.y);
 
-    /* position */
-    res.x = layout->position.x;
-    res.y = layout->position.y;
+		/* position */
+		res.x = layout->position.x;
+		res.y = layout->position.y;
 
-    /* size */
-    res.w =
-      layout->items > -1 ? layout->widths[layout->row_index] : layout->size.x;
-    res.h = layout->size.y;
-    if (res.w == 0) { res.w = style->size.x + style->padding * 2; }
-    if (res.h == 0) { res.h = style->size.y + style->padding * 2; }
-    if (res.w <  0) { res.w += layout->body.w - res.x + 1; }
-    if (res.h <  0) { res.h += layout->body.h - res.y + 1; }
+		/* size */
+		res.w = layout->items > -1 ? layout->widths[layout->row_index] : layout->size.x;
+		res.h = layout->size.y;
+		if (res.w == 0) { res.w = style->size.x + style->padding * 2; }
+		if (res.h == 0) { res.h = style->size.y + style->padding * 2; }
+		if (res.w <	0) { res.w += layout->body.w - res.x + 1; }
+		if (res.h <	0) { res.h += layout->body.h - res.y + 1; }
 
-    layout->row_index++;
-  }
+		layout->row_index++;
+	}
 
-  /* update position */
-  layout->position.x += res.w + style->spacing;
-  layout->next_row = mu_max(layout->next_row, res.y + res.h + style->spacing);
+	/* update position */
+	layout->position.x += res.w + style->spacing;
+	layout->next_row = max(layout->next_row, res.y + res.h + style->spacing);
 
-  /* apply body offset */
-  res.x += layout->body.x;
-  res.y += layout->body.y;
+	/* apply body offset */
+	res.x += layout->body.x;
+	res.y += layout->body.y;
 
-  /* update max position */
-  layout->max.x = mu_max(layout->max.x, res.x + res.w);
-  layout->max.y = mu_max(layout->max.y, res.y + res.h);
+	/* update max position */
+	layout->max.x = max(layout->max.x, res.x + res.w);
+	layout->max.y = max(layout->max.y, res.y + res.h);
 
-  ctx->last_rect = res;
-  return res;
+	ctx->last_rect = res;
+	return res;
 }
 
 
@@ -644,621 +719,689 @@
 ** controls
 **============================================================================*/
 
-static int in_hover_root(mu_Context *ctx) {
-  int i = ctx->container_stack.idx;
-  while (i--) {
-    if (ctx->container_stack.items[i] == ctx->last_hover_root) { return 1; }
-    /* only root containers have their `head` field set; stop searching if we've
-    ** reached the current root container */
-    if (ctx->container_stack.items[i]->head) { break; }
-  }
-  return 0;
+static int
+in_hover_root(mu_Context *ctx)
+{
+	int i = ctx->cntnum;
+	while (i--) {
+		if (ctx->cnt[i] == ctx->last_hover_root)
+			return 1;
+		/* only root containers have their `head` field set; stop searching if we've
+		** reached the current root container */
+		if (ctx->cnt[i]->head >= 0)
+			break;
+	}
+	return 0;
 }
 
 
-void mu_draw_control_frame(mu_Context *ctx, mu_Id id, mu_Rect rect,
-  int colorid, int opt)
+void
+mu_draw_control_frame(mu_Context *ctx, mu_Id id, mu_Rect rect, int colorid, int opt)
 {
-  if (opt & MU_OPT_NOFRAME) { return; }
-  colorid += (ctx->focus == id) ? 2 : (ctx->hover == id) ? 1 : 0;
-  draw_frame(ctx, rect, colorid);
+	if (opt & MU_OPT_NOFRAME)
+		return;
+	colorid += (ctx->focus == id) ? 2 : (ctx->hover == id) ? 1 : 0;
+	draw_frame(ctx, rect, colorid);
 }
 
 
-void mu_draw_control_text(mu_Context *ctx, const char *str, mu_Rect rect,
-  int colorid, int opt)
+void
+mu_draw_control_text(mu_Context *ctx, const char *str, mu_Rect rect, int colorid, int opt)
 {
-  Point pos;
-  Font *font = ctx->style->font;
-  int tw = text_width(font, str, -1);
-  mu_push_clip_rect(ctx, rect);
-  pos.y = rect.y + (rect.h - font->height) / 2;
-  if (opt & MU_OPT_ALIGNCENTER) {
-    pos.x = rect.x + (rect.w - tw) / 2;
-  } else if (opt & MU_OPT_ALIGNRIGHT) {
-    pos.x = rect.x + rect.w - tw - ctx->style->padding;
-  } else {
-    pos.x = rect.x + ctx->style->padding;
-  }
-  mu_draw_text(ctx, font, str, -1, pos, ctx->style->colors[colorid]);
-  mu_pop_clip_rect(ctx);
+	Point pos;
+	Font *font = ctx->style->font;
+	int tw = text_width(font, str, -1);
+	mu_push_clip_rect(ctx, rect);
+	pos.y = rect.y + (rect.h - font->height) / 2;
+	if (opt & MU_OPT_ALIGNCENTER)
+		pos.x = rect.x + (rect.w - tw) / 2;
+	else if (opt & MU_OPT_ALIGNRIGHT)
+		pos.x = rect.x + rect.w - tw - ctx->style->padding;
+	else
+		pos.x = rect.x + ctx->style->padding;
+
+	mu_draw_text(ctx, font, str, -1, pos, ctx->style->colors[colorid]);
+	mu_pop_clip_rect(ctx);
 }
 
 
-int mu_mouse_over(mu_Context *ctx, mu_Rect rect) {
-  return rect_overlaps_vec2(rect, ctx->mouse_pos) &&
-    rect_overlaps_vec2(mu_get_clip_rect(ctx), ctx->mouse_pos) &&
-    in_hover_root(ctx);
+int
+mu_mouse_over(mu_Context *ctx, mu_Rect rect)
+{
+	return rect_overlaps_vec2(rect, ctx->mouse_pos) &&
+		rect_overlaps_vec2(mu_get_clip_rect(ctx), ctx->mouse_pos) &&
+		in_hover_root(ctx);
 }
 
 
-void mu_update_control(mu_Context *ctx, mu_Id id, mu_Rect rect, int opt) {
-  int mouseover = mu_mouse_over(ctx, rect);
+void
+mu_update_control(mu_Context *ctx, mu_Id id, mu_Rect rect, int opt)
+{
+	int mouseover = mu_mouse_over(ctx, rect);
 
-  if (ctx->focus == id) { ctx->updated_focus = 1; }
-  if (opt & MU_OPT_NOINTERACT) { return; }
-  if (mouseover && !ctx->mouse_down) { ctx->hover = id; }
+	if (ctx->focus == id)
+		ctx->updated_focus = 1;
+	if (opt & MU_OPT_NOINTERACT)
+		return;
+	if (mouseover && !ctx->mouse_down)
+		ctx->hover = id;
 
-  if (ctx->focus == id) {
-    if (ctx->mouse_pressed && !mouseover) { mu_set_focus(ctx, 0); }
-    if (!ctx->mouse_down && ~opt & MU_OPT_HOLDFOCUS) { mu_set_focus(ctx, 0); }
-  }
+	if (ctx->focus == id) {
+		if (ctx->mouse_pressed && !mouseover)
+			mu_set_focus(ctx, 0);
+		if (!ctx->mouse_down && ~opt & MU_OPT_HOLDFOCUS)
+			mu_set_focus(ctx, 0);
+	}
 
-  if (ctx->hover == id) {
-    if (!mouseover) {
-      ctx->hover = 0;
-    } else if (ctx->mouse_pressed) {
-      mu_set_focus(ctx, id);
-    }
-  }
+	if (ctx->hover == id) {
+		if (!mouseover)
+			ctx->hover = 0;
+		else if (ctx->mouse_pressed)
+			mu_set_focus(ctx, id);
+	}
 }
 
 
-void mu_text(mu_Context *ctx, const char *text) {
-  const char *start, *end, *p = text;
-  int width = -1;
-  Font *font = ctx->style->font;
-  Image *color = ctx->style->colors[MU_COLOR_TEXT];
-  mu_layout_begin_column(ctx);
-  mu_layout_row(ctx, 1, &width, font->height);
-  do {
-    mu_Rect r = mu_layout_next(ctx);
-    int w = 0;
-    start = end = p;
-    do {
-      const char* word = p;
-      while (*p && *p != ' ' && *p != '\n') { p++; }
-      w += text_width(font, word, p - word);
-      if (w > r.w && end != start) { break; }
-      w += text_width(font, p, 1);
-      end = p++;
-    } while (*end && *end != '\n');
-    mu_draw_text(ctx, font, start, end - start, Pt(r.x, r.y), color);
-    p = end + 1;
-  } while (*end);
-  mu_layout_end_column(ctx);
+void
+mu_text(mu_Context *ctx, const char *text)
+{
+	const char *start, *end, *p = text;
+	int width = -1;
+	Font *font = ctx->style->font;
+	Image *color = ctx->style->colors[MU_COLOR_TEXT];
+	mu_layout_begin_column(ctx);
+	mu_layout_row(ctx, 1, &width, font->height);
+	do {
+		mu_Rect r = mu_layout_next(ctx);
+		int w = 0;
+		start = end = p;
+		do {
+			const char* word = p;
+			while (*p && *p != ' ' && *p != '\n')
+				p++;
+			w += text_width(font, word, p - word);
+			if (w > r.w && end != start)
+				break;
+			w += text_width(font, p, 1);
+			end = p++;
+		} while (*end && *end != '\n');
+		mu_draw_text(ctx, font, start, end - start, Pt(r.x, r.y), color);
+		p = end + 1;
+	} while (*end);
+	mu_layout_end_column(ctx);
 }
 
 
-void mu_label(mu_Context *ctx, const char *text) {
-  mu_draw_control_text(ctx, text, mu_layout_next(ctx), MU_COLOR_TEXT, 0);
+void
+mu_label(mu_Context *ctx, const char *text)
+{
+	mu_draw_control_text(ctx, text, mu_layout_next(ctx), MU_COLOR_TEXT, 0);
 }
 
 
-int mu_button_ex(mu_Context *ctx, const char *label, int icon, int opt) {
-  int res = 0;
-  mu_Id id = label ? mu_get_id(ctx, label, strlen(label))
-    : mu_get_id(ctx, &icon, sizeof(icon));
-  mu_Rect r = mu_layout_next(ctx);
-  mu_update_control(ctx, id, r, opt);
-  /* handle click */
-  if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) {
-    res |= MU_RES_SUBMIT;
-  }
-  /* draw */
-  mu_draw_control_frame(ctx, id, r, MU_COLOR_BUTTON, opt);
-  if (label) { mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, opt); }
-  if (icon) { mu_draw_icon(ctx, icon, r); }
-  return res;
+int
+mu_button_ex(mu_Context *ctx, const char *label, int icon, int opt) {
+	int res = 0;
+	mu_Id id = label ? mu_get_id(ctx, label, strlen(label)) : mu_get_id(ctx, &icon, sizeof(icon));
+	mu_Rect r = mu_layout_next(ctx);
+	mu_update_control(ctx, id, r, opt);
+	/* handle click */
+	if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id)
+		res |= MU_RES_SUBMIT;
+
+	/* draw */
+	mu_draw_control_frame(ctx, id, r, MU_COLOR_BUTTON, opt);
+	if (label)
+		mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, opt);
+	if (icon)
+		mu_draw_icon(ctx, icon, r);
+	return res;
 }
 
 
-int mu_button(mu_Context *ctx, const char *label) {
-  return mu_button_ex(ctx, label, 0, MU_OPT_ALIGNCENTER);
+int
+mu_button(mu_Context *ctx, const char *label)
+{
+	return mu_button_ex(ctx, label, 0, MU_OPT_ALIGNCENTER);
 }
 
 
-int mu_checkbox(mu_Context *ctx, int *state, const char *label) {
-  int res = 0;
-  mu_Id id = mu_get_id(ctx, &state, sizeof(state));
-  mu_Rect r = mu_layout_next(ctx);
-  mu_Rect box = mu_rect(r.x, r.y, r.h, r.h);
-  mu_update_control(ctx, id, r, 0);
-  /* handle click */
-  if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) {
-    res |= MU_RES_CHANGE;
-    *state = !*state;
-  }
-  /* draw */
-  mu_draw_control_frame(ctx, id, box, MU_COLOR_BASE, 0);
-  if (*state) {
-    mu_draw_icon(ctx, MU_ICON_CHECK, box);
-  }
-  r = mu_rect(r.x + box.w, r.y, r.w - box.w, r.h);
-  mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, 0);
-  return res;
+int
+mu_checkbox(mu_Context *ctx, int *state, const char *label)
+{
+	int res = 0;
+	mu_Id id = mu_get_id(ctx, &state, sizeof(state));
+	mu_Rect r = mu_layout_next(ctx);
+	mu_Rect box = mu_rect(r.x, r.y, r.h, r.h);
+	mu_update_control(ctx, id, r, 0);
+	/* handle click */
+	if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) {
+		res |= MU_RES_CHANGE;
+		*state = !*state;
+	}
+	/* draw */
+	mu_draw_control_frame(ctx, id, box, MU_COLOR_BASE, 0);
+	if (*state)
+		mu_draw_icon(ctx, MU_ICON_CHECK, box);
+
+	r = mu_rect(r.x + box.w, r.y, r.w - box.w, r.h);
+	mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, 0);
+	return res;
 }
 
 
-int mu_textbox_raw(mu_Context *ctx, char *buf, int bufsz, mu_Id id, mu_Rect r,
-  int opt)
+int
+mu_textbox_raw(mu_Context *ctx, char *buf, int bufsz, mu_Id id, mu_Rect r, int opt)
 {
-  int res = 0;
-  mu_update_control(ctx, id, r, opt | MU_OPT_HOLDFOCUS);
+	int res = 0;
+	mu_update_control(ctx, id, r, opt | MU_OPT_HOLDFOCUS);
 
-  if (ctx->focus == id) {
-    /* handle text input */
-    int len = strlen(buf);
-    int n = mu_min(bufsz - len - 1, (int) strlen(ctx->text_input));
-    if (n > 0) {
-      memcpy(buf + len, ctx->text_input, n);
-      len += n;
-      buf[len] = '\0';
-      res |= MU_RES_CHANGE;
-    }
-    /* handle backspace */
-    if (ctx->key_pressed & MU_KEY_BACKSPACE && len > 0) {
-      /* skip utf-8 continuation bytes */
-      while ((buf[--len] & 0xc0) == 0x80 && len > 0);
-      buf[len] = '\0';
-      res |= MU_RES_CHANGE;
-    }
-    if (ctx->key_pressed & MU_KEY_NACK && len > 0) {
-      buf[0] = '\0';
-      res |= MU_RES_CHANGE;
-    }
-    /* handle return */
-    if (ctx->key_pressed & MU_KEY_RETURN) {
-      mu_set_focus(ctx, 0);
-      res |= MU_RES_SUBMIT;
-    }
-  }
+	if (ctx->focus == id) {
+		/* handle text input */
+		int len = strlen(buf);
+		int n = min(bufsz - len - 1, (int) strlen(ctx->text_input));
+		if (n > 0) {
+			memcpy(buf + len, ctx->text_input, n);
+			len += n;
+			buf[len] = '\0';
+			res |= MU_RES_CHANGE;
+		}
+		/* handle backspace */
+		if (ctx->key_pressed & MU_KEY_BACKSPACE && len > 0) {
+			/* skip utf-8 continuation bytes */
+			while ((buf[--len] & 0xc0) == 0x80 && len > 0);
+			buf[len] = '\0';
+			res |= MU_RES_CHANGE;
+		}
+		if (ctx->key_pressed & MU_KEY_NACK && len > 0) {
+			buf[0] = '\0';
+			res |= MU_RES_CHANGE;
+		}
+		/* handle return */
+		if (ctx->key_pressed & MU_KEY_RETURN) {
+			mu_set_focus(ctx, 0);
+			res |= MU_RES_SUBMIT;
+		}
+	}
 
-  /* draw */
-  mu_draw_control_frame(ctx, id, r, MU_COLOR_BASE, opt);
-  if (ctx->focus == id) {
-    Image *color = ctx->style->colors[MU_COLOR_TEXT];
-    Font *font = ctx->style->font;
-    int textw = text_width(font, buf, -1);
-    int texth = font->height;
-    int ofx = r.w - ctx->style->padding - textw - 1;
-    int textx = r.x + mu_min(ofx, ctx->style->padding);
-    int texty = r.y + (r.h - texth) / 2;
-    mu_push_clip_rect(ctx, r);
-    mu_draw_text(ctx, font, buf, -1, Pt(textx, texty), color);
-    mu_draw_rect(ctx, mu_rect(textx + textw, texty, 1, texth), color);
-    mu_pop_clip_rect(ctx);
-  } else {
-    mu_draw_control_text(ctx, buf, r, MU_COLOR_TEXT, opt);
-  }
+	/* draw */
+	mu_draw_control_frame(ctx, id, r, MU_COLOR_BASE, opt);
+	if (ctx->focus == id) {
+		Image *color = ctx->style->colors[MU_COLOR_TEXT];
+		Font *font = ctx->style->font;
+		int textw = text_width(font, buf, -1);
+		int texth = font->height;
+		int ofx = r.w - ctx->style->padding - textw - 1;
+		int textx = r.x + min(ofx, ctx->style->padding);
+		int texty = r.y + (r.h - texth) / 2;
+		mu_push_clip_rect(ctx, r);
+		mu_draw_text(ctx, font, buf, -1, Pt(textx, texty), color);
+		mu_draw_rect(ctx, mu_rect(textx + textw, texty, 1, texth), color);
+		mu_pop_clip_rect(ctx);
+	} else {
+		mu_draw_control_text(ctx, buf, r, MU_COLOR_TEXT, opt);
+	}
 
-  return res;
+	return res;
 }
 
 
-static int number_textbox(mu_Context *ctx, float *value, mu_Rect r, mu_Id id) {
-  if (((ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->key_down & MU_KEY_SHIFT)
-       ||
-       ctx->mouse_pressed == MU_MOUSE_RIGHT
-      ) &&
-      ctx->hover == id)
-  {
-    ctx->number_editing = id;
-    sprint(ctx->number_buf, MU_REAL_FMT, *value);
-  }
-  if (ctx->number_editing == id) {
-    int res = mu_textbox_raw(
-      ctx, ctx->number_buf, sizeof(ctx->number_buf), id, r, 0);
-    if (res & MU_RES_SUBMIT || ctx->focus != id) {
-      *value = strtod(ctx->number_buf, nil);
-      ctx->number_editing = 0;
-    } else {
-      return 1;
-    }
-  }
-  return 0;
+static int
+number_textbox(mu_Context *ctx, float *value, mu_Rect r, mu_Id id)
+{
+	if (((ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->key_down & MU_KEY_SHIFT) || ctx->mouse_pressed == MU_MOUSE_RIGHT) && ctx->hover == id) {
+		ctx->number_editing = id;
+		sprint(ctx->number_buf, MU_REAL_FMT, *value);
+	}
+	if (ctx->number_editing == id) {
+		int res = mu_textbox_raw(ctx, ctx->number_buf, sizeof(ctx->number_buf), id, r, 0);
+		if (res & MU_RES_SUBMIT || ctx->focus != id) {
+			*value = strtod(ctx->number_buf, nil);
+			ctx->number_editing = 0;
+		} else {
+			return 1;
+		}
+	}
+	return 0;
 }
 
 
-int mu_textbox_ex(mu_Context *ctx, char *buf, int bufsz, int opt) {
-  mu_Id id = mu_get_id(ctx, &buf, sizeof(buf));
-  mu_Rect r = mu_layout_next(ctx);
-  return mu_textbox_raw(ctx, buf, bufsz, id, r, opt);
+int
+mu_textbox_ex(mu_Context *ctx, char *buf, int bufsz, int opt)
+{
+	mu_Id id = mu_get_id(ctx, &buf, sizeof(buf));
+	mu_Rect r = mu_layout_next(ctx);
+	return mu_textbox_raw(ctx, buf, bufsz, id, r, opt);
 }
 
 
-int mu_textbox(mu_Context *ctx, char *buf, int bufsz) {
-  return mu_textbox_ex(ctx, buf, bufsz, 0);
+int
+mu_textbox(mu_Context *ctx, char *buf, int bufsz)
+{
+	return mu_textbox_ex(ctx, buf, bufsz, 0);
 }
 
 
-int mu_slider_ex(mu_Context *ctx, float *value, float low, float high,
-  float step, const char *fmt, int opt)
+int
+mu_slider_ex(mu_Context *ctx, float *value, float low, float high, float step, const char *fmt, int opt)
 {
-  char buf[MU_MAX_FMT + 1];
-  mu_Rect thumb;
-  int w, res = 0;
-  float normalized, last = *value, v = last;
-  mu_Id id = mu_get_id(ctx, &value, sizeof(value));
-  mu_Rect base = mu_layout_next(ctx);
+	char buf[MU_MAX_FMT + 1];
+	mu_Rect thumb;
+	int w, res = 0;
+	float normalized, last = *value, v = last;
+	mu_Id id = mu_get_id(ctx, &value, sizeof(value));
+	mu_Rect base = mu_layout_next(ctx);
 
-  /* handle text input mode */
-  if (number_textbox(ctx, &v, base, id)) { return res; }
+	/* handle text input mode */
+	if (number_textbox(ctx, &v, base, id))
+		return res;
 
-  /* handle normal mode */
-  mu_update_control(ctx, id, base, opt);
+	/* handle normal mode */
+	mu_update_control(ctx, id, base, opt);
 
-  /* handle input */
-  if (ctx->focus == id) {
-    if (ctx->mouse_down == MU_MOUSE_LEFT) {
-      v = low + ((float) (ctx->mouse_pos.x - base.x) / base.w) * (high - low);
-    }
-  } else if (ctx->hover == id) {
-    if ((ctx->key_pressed & (MU_KEY_LEFT | MU_KEY_RIGHT)) == MU_KEY_LEFT) {
-      v -= step ? step : 1;
-      if (v < low) v = low;
-    } else if ((ctx->key_pressed & (MU_KEY_LEFT | MU_KEY_RIGHT)) == MU_KEY_RIGHT) {
-      v += step ? step : 1;
-      if (v > high) v = high;
-    }
-  }
+	/* handle input */
+	if (ctx->focus == id) {
+		if (ctx->mouse_down == MU_MOUSE_LEFT)
+			v = low + ((float) (ctx->mouse_pos.x - base.x) / base.w) * (high - low);
+	} else if (ctx->hover == id) {
+		if ((ctx->key_pressed & (MU_KEY_LEFT | MU_KEY_RIGHT)) == MU_KEY_LEFT) {
+			v -= step ? step : 1;
+			if (v < low) v = low;
+		} else if ((ctx->key_pressed & (MU_KEY_LEFT | MU_KEY_RIGHT)) == MU_KEY_RIGHT) {
+			v += step ? step : 1;
+			if (v > high) v = high;
+		}
+	}
 
-  if (step) { v = ((long) ((v + step/2) / step)) * step; }
-  /* clamp and store value, update res */
-  *value = v = mu_clamp(v, low, high);
-  if (last != v) { res |= MU_RES_CHANGE; }
+	if (step)
+		v = ((long) ((v + step/2) / step)) * step;
+	/* clamp and store value, update res */
+	*value = v = clamp(v, low, high);
+	if (last != v)
+		res |= MU_RES_CHANGE;
 
-  /* draw base */
-  mu_draw_control_frame(ctx, id, base, MU_COLOR_BASE, opt);
-  /* draw thumb */
-  w = ctx->style->thumb_size;
-  normalized = (v - low) / (high - low);
-  thumb = mu_rect(base.x + normalized * (base.w - w), base.y, w, base.h);
-  mu_draw_control_frame(ctx, id, thumb, MU_COLOR_BUTTON, opt);
-  /* draw text  */
-  sprint(buf, fmt, v);
-  mu_draw_control_text(ctx, buf, base, MU_COLOR_TEXT, opt);
+	/* draw base */
+	mu_draw_control_frame(ctx, id, base, MU_COLOR_BASE, opt);
+	/* draw thumb */
+	w = ctx->style->thumb_size;
+	normalized = (v - low) / (high - low);
+	thumb = mu_rect(base.x + normalized * (base.w - w), base.y, w, base.h);
+	mu_draw_control_frame(ctx, id, thumb, MU_COLOR_BUTTON, opt);
+	/* draw text	*/
+	sprint(buf, fmt, v);
+	mu_draw_control_text(ctx, buf, base, MU_COLOR_TEXT, opt);
 
-  return res;
+	return res;
 }
 
 
-int mu_slider(mu_Context *ctx, float *value, float low, float high) {
-  return mu_slider_ex(ctx, value, low, high, 0, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER);
+int
+mu_slider(mu_Context *ctx, float *value, float low, float high)
+{
+	return mu_slider_ex(ctx, value, low, high, 0, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER);
 }
 
 
-int mu_number_ex(mu_Context *ctx, float *value, float step,
-  const char *fmt,int opt)
+int
+mu_number_ex(mu_Context *ctx, float *value, float step, const char *fmt, int opt)
 {
-  char buf[MU_MAX_FMT + 1];
-  int res = 0;
-  mu_Id id = mu_get_id(ctx, &value, sizeof(value));
-  mu_Rect base = mu_layout_next(ctx);
-  float last = *value;
+	char buf[MU_MAX_FMT + 1];
+	int res = 0;
+	mu_Id id = mu_get_id(ctx, &value, sizeof(value));
+	mu_Rect base = mu_layout_next(ctx);
+	float last = *value;
 
-  /* handle text input mode */
-  if (number_textbox(ctx, value, base, id)) { return res; }
+	/* handle text input mode */
+	if (number_textbox(ctx, value, base, id))
+		return res;
 
-  /* handle normal mode */
-  mu_update_control(ctx, id, base, opt);
+	/* handle normal mode */
+	mu_update_control(ctx, id, base, opt);
 
-  /* handle input */
-  if (ctx->focus == id && ctx->mouse_down == MU_MOUSE_LEFT) {
-    *value += ctx->mouse_delta.x * step;
-  }
-  /* set flag if value changed */
-  if (*value != last) { res |= MU_RES_CHANGE; }
+	/* handle input */
+	if (ctx->focus == id && ctx->mouse_down == MU_MOUSE_LEFT)
+		*value += ctx->mouse_delta.x * step;
 
-  /* draw base */
-  mu_draw_control_frame(ctx, id, base, MU_COLOR_BASE, opt);
-  /* draw text  */
-  sprint(buf, fmt, *value);
-  mu_draw_control_text(ctx, buf, base, MU_COLOR_TEXT, opt);
+	/* set flag if value changed */
+	if (*value != last)
+		res |= MU_RES_CHANGE;
 
-  return res;
+	/* draw base */
+	mu_draw_control_frame(ctx, id, base, MU_COLOR_BASE, opt);
+	/* draw text	*/
+	sprint(buf, fmt, *value);
+	mu_draw_control_text(ctx, buf, base, MU_COLOR_TEXT, opt);
+
+	return res;
 }
 
 
-int mu_number(mu_Context *ctx, float *value, float step) {
-  return mu_number_ex(ctx, value, step, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER);
+int
+mu_number(mu_Context *ctx, float *value, float step)
+{
+	return mu_number_ex(ctx, value, step, MU_SLIDER_FMT, MU_OPT_ALIGNCENTER);
 }
 
 
-static int header(mu_Context *ctx, int *state, const char *label,
-  int istreenode)
+static int
+header(mu_Context *ctx, int *state, const char *label, int istreenode)
 {
-  mu_Rect r;
-  mu_Id id;
-  int width = -1;
-  mu_layout_row(ctx, 1, &width, 0);
-  r = mu_layout_next(ctx);
-  id = mu_get_id(ctx, &state, sizeof(state));
-  mu_update_control(ctx, id, r, 0);
-  /* handle click */
-  if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id) {
-    *state = !(*state);
-  }
-  /* draw */
-  if (istreenode) {
-    if (ctx->hover == id) { draw_frame(ctx, r, MU_COLOR_BUTTONHOVER); }
-  } else {
-    mu_draw_control_frame(ctx, id, r, MU_COLOR_BUTTON, 0);
-  }
-  mu_draw_icon(
-    ctx, *state ? MU_ICON_EXPANDED : MU_ICON_COLLAPSED,
-    mu_rect(r.x, r.y, r.h, r.h));
-  r.x += r.h - ctx->style->padding;
-  r.w -= r.h - ctx->style->padding;
-  mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, 0);
-  return *state ? MU_RES_ACTIVE : 0;
+	mu_Rect r;
+	mu_Id id;
+	int width = -1;
+	mu_layout_row(ctx, 1, &width, 0);
+	r = mu_layout_next(ctx);
+	id = mu_get_id(ctx, &state, sizeof(state));
+	mu_update_control(ctx, id, r, 0);
+	/* handle click */
+	if (ctx->mouse_pressed == MU_MOUSE_LEFT && ctx->focus == id)
+		*state = !(*state);
+
+	/* draw */
+	if (istreenode) {
+		if (ctx->hover == id)
+			draw_frame(ctx, r, MU_COLOR_BUTTONHOVER);
+	} else {
+		mu_draw_control_frame(ctx, id, r, MU_COLOR_BUTTON, 0);
+	}
+	mu_draw_icon(
+		ctx, *state ? MU_ICON_EXPANDED : MU_ICON_COLLAPSED,
+		mu_rect(r.x, r.y, r.h, r.h));
+	r.x += r.h - ctx->style->padding;
+	r.w -= r.h - ctx->style->padding;
+	mu_draw_control_text(ctx, label, r, MU_COLOR_TEXT, 0);
+	return *state ? MU_RES_ACTIVE : 0;
 }
 
 
-int mu_header(mu_Context *ctx, int *state, const char *label) {
-  return header(ctx, state, label, 0);
+int
+mu_header(mu_Context *ctx, int *state, const char *label)
+{
+	return header(ctx, state, label, 0);
 }
 
 
-int mu_begin_treenode(mu_Context *ctx, int *state, const char *label) {
-  int res = header(ctx, state, label, 1);
-  if (res & MU_RES_ACTIVE) {
-    get_layout(ctx)->indent += ctx->style->indent;
-    mu_push_id(ctx, &state, sizeof(void*));
-  }
-  return res;
+int
+mu_begin_treenode(mu_Context *ctx, int *state, const char *label)
+{
+	int res = header(ctx, state, label, 1);
+	if (res & MU_RES_ACTIVE) {
+		get_layout(ctx)->indent += ctx->style->indent;
+		mu_push_id(ctx, &state, sizeof(void*));
+	}
+	return res;
 }
 
 
-void mu_end_treenode(mu_Context *ctx) {
-  get_layout(ctx)->indent -= ctx->style->indent;
-  mu_pop_id(ctx);
+void
+mu_end_treenode(mu_Context *ctx)
+{
+	get_layout(ctx)->indent -= ctx->style->indent;
+	mu_pop_id(ctx);
 }
 
 
-#define scrollbar(ctx, cnt, b, cs, x, y, w, h)                              \
-  do {                                                                      \
-    /* only add scrollbar if content size is larger than body */            \
-    int maxscroll = cs.y - b->h;                                            \
-                                                                            \
-    if (maxscroll > 0 && b->h > 0) {                                        \
-      mu_Rect base, thumb;                                                  \
-      mu_Id id = mu_get_id(ctx, "!scrollbar" #y, 11);                       \
-                                                                            \
-      /* get sizing / positioning */                                        \
-      base = *b;                                                            \
-      base.x = b->x + b->w;                                                 \
-      base.w = ctx->style->scrollbar_size;                                  \
-                                                                            \
-      /* handle input */                                                    \
-      mu_update_control(ctx, id, base, 0);                                  \
-      if (ctx->focus == id && ctx->mouse_down == MU_MOUSE_LEFT) {           \
-        cnt->scroll.y += ctx->mouse_delta.y * cs.y / base.h;                \
-      }                                                                     \
-      /* clamp scroll to limits */                                          \
-      cnt->scroll.y = mu_clamp(cnt->scroll.y, 0, maxscroll);                \
-                                                                            \
-      /* draw base and thumb */                                             \
-      draw_frame(ctx, base, MU_COLOR_SCROLLBASE);                      \
-      thumb = base;                                                         \
-      thumb.h = mu_max(ctx->style->thumb_size, base.h * b->h / cs.y);       \
-      thumb.y += cnt->scroll.y * (base.h - thumb.h) / maxscroll;            \
-      draw_frame(ctx, thumb, MU_COLOR_SCROLLTHUMB);                    \
-                                                                            \
-      /* set this as the scroll_target (will get scrolled on mousewheel) */ \
-      /* if the mouse is over it */                                         \
-      if (mu_mouse_over(ctx, *b)) { ctx->scroll_target = cnt; }             \
-    } else {                                                                \
-      cnt->scroll.y = 0;                                                    \
-    }                                                                       \
-  } while (0)
+#define scrollbar(ctx, cnt, b, cs, x, y, w, h) \
+	do { \
+		/* only add scrollbar if content size is larger than body */ \
+		int maxscroll = cs.y - b->h; \
+ \
+		if (maxscroll > 0 && b->h > 0) { \
+			mu_Rect base, thumb; \
+			mu_Id id = mu_get_id(ctx, "!scrollbar" #y, 11); \
+ \
+			/* get sizing / positioning */ \
+			base = *b; \
+			base.x = b->x + b->w; \
+			base.w = ctx->style->scrollbar_size; \
+ \
+			/* handle input */ \
+			mu_update_control(ctx, id, base, 0); \
+			if (ctx->focus == id && ctx->mouse_down == MU_MOUSE_LEFT) { \
+				cnt->scroll.y += ctx->mouse_delta.y * cs.y / base.h; \
+			} \
+			/* clamp scroll to limits */ \
+			cnt->scroll.y = clamp(cnt->scroll.y, 0, maxscroll); \
+ \
+			/* draw base and thumb */ \
+			draw_frame(ctx, base, MU_COLOR_SCROLLBASE); \
+			thumb = base; \
+			thumb.h = max(ctx->style->thumb_size, base.h * b->h / cs.y); \
+			thumb.y += cnt->scroll.y * (base.h - thumb.h) / maxscroll; \
+			draw_frame(ctx, thumb, MU_COLOR_SCROLLTHUMB); \
+ \
+			/* set this as the scroll_target (will get scrolled on mousewheel) */ \
+			/* if the mouse is over it */ \
+			if (mu_mouse_over(ctx, *b)) { ctx->scroll_target = cnt; } \
+		} else { \
+			cnt->scroll.y = 0; \
+		} \
+	} while (0)
 
-
-static void scrollbars(mu_Context *ctx, mu_Container *cnt, mu_Rect *body) {
-  int sz = ctx->style->scrollbar_size;
-  Point cs = cnt->content_size;
-  cs.x += ctx->style->padding * 2;
-  cs.y += ctx->style->padding * 2;
-  mu_push_clip_rect(ctx, *body);
-  /* resize body to make room for scrollbars */
-  if (cs.y > cnt->body.h) { body->w -= sz; }
-  if (cs.x > cnt->body.w) { body->h -= sz; }
-  /* to create a horizontal or vertical scrollbar almost-identical code is
-  ** used; only the references to `x|y` `w|h` need to be switched */
-  scrollbar(ctx, cnt, body, cs, x, y, w, h);
-  scrollbar(ctx, cnt, body, cs, y, x, h, w);
-  mu_pop_clip_rect(ctx);
+static void
+scrollbars(mu_Context *ctx, mu_Container *cnt, mu_Rect *body)
+{
+	int sz = ctx->style->scrollbar_size;
+	Point cs = cnt->content_size;
+	cs.x += ctx->style->padding * 2;
+	cs.y += ctx->style->padding * 2;
+	mu_push_clip_rect(ctx, *body);
+	/* resize body to make room for scrollbars */
+	if (cs.y > cnt->body.h)
+		body->w -= sz;
+	if (cs.x > cnt->body.w)
+		body->h -= sz;
+	/* to create a horizontal or vertical scrollbar almost-identical code is
+	** used; only the references to `x|y` `w|h` need to be switched */
+	scrollbar(ctx, cnt, body, cs, x, y, w, h);
+	scrollbar(ctx, cnt, body, cs, y, x, h, w);
+	mu_pop_clip_rect(ctx);
 }
 
 
-static void push_container_body(
-  mu_Context *ctx, mu_Container *cnt, mu_Rect body, int opt
-) {
-  if (~opt & MU_OPT_NOSCROLL) { scrollbars(ctx, cnt, &body); }
-  push_layout(ctx, expand_rect(body, -ctx->style->padding), cnt->scroll);
-  cnt->body = body;
+static void
+push_container_body(mu_Context *ctx, mu_Container *cnt, mu_Rect body, int opt)
+{
+	if (~opt & MU_OPT_NOSCROLL)
+		scrollbars(ctx, cnt, &body);
+	push_layout(ctx, expand_rect(body, -ctx->style->padding), cnt->scroll);
+	cnt->body = body;
 }
 
 
-static void begin_root_container(mu_Context *ctx, mu_Container *cnt) {
-  push_container(ctx, cnt);
+static void
+begin_root_container(mu_Context *ctx, mu_Container *cnt)
+{
+	push_container(ctx, cnt);
 
-  /* push container to roots list and push head command */
-  push(ctx->root_list, cnt);
-  cnt->head = push_jump(ctx, nil);
+	/* push container to roots list and push head command */
+	buffer_grow(&ctx->root, sizeof(*ctx->root), &ctx->rootmax, ctx->rootnum);
+	ctx->root[ctx->rootnum++] = cnt;
+	cnt->head = push_jump(ctx, -1);
 
-  /* set as hover root if the mouse is overlapping this container and it has a
-  ** higher zindex than the current hover root */
-  if (rect_overlaps_vec2(cnt->rect, ctx->mouse_pos) &&
-      (!ctx->hover_root || cnt->zindex > ctx->hover_root->zindex))
-  {
-    ctx->hover_root = cnt;
-  }
-  /* clipping is reset here in case a root-container is made within
-  ** another root-containers's begin/end block; this prevents the inner
-  ** root-container being clipped to the outer */
-  push(ctx->clip_stack, unclipped_rect);
+	/* set as hover root if the mouse is overlapping this container and it has a
+	** higher zindex than the current hover root */
+	if (rect_overlaps_vec2(cnt->rect, ctx->mouse_pos) && (!ctx->hover_root || cnt->zindex > ctx->hover_root->zindex))
+		ctx->hover_root = cnt;
+
+	/* clipping is reset here in case a root-container is made within
+	** another root-containers's begin/end block; this prevents the inner
+	** root-container being clipped to the outer */
+	buffer_grow(&ctx->clip, sizeof(*ctx->clip), &ctx->clipmax, ctx->clipnum);
+	ctx->clip[ctx->clipnum++] = unclipped_rect;
 }
 
 
-static void end_root_container(mu_Context *ctx) {
-  /* push tail 'goto' jump command and set head 'skip' command. the final steps
-  ** on initing these are done in mu_end() */
-  mu_Container *cnt = mu_get_container(ctx);
-  cnt->tail = push_jump(ctx, nil);
-  cnt->head->jump.dst = ctx->command_list.items + ctx->command_list.idx;
-  /* pop base clip rect and container */
-  mu_pop_clip_rect(ctx);
-  pop_container(ctx);
+static void
+end_root_container(mu_Context *ctx)
+{
+	/* push tail 'goto' jump command and set head 'skip' command. the final steps
+	** on initing these are done in mu_end() */
+	mu_Container *cnt = mu_get_container(ctx);
+	cnt->tail = push_jump(ctx, -1);
+	ctx->cmds[cnt->head].jump.dst = ctx->cmdsnum;
+	/* pop base clip rect and container */
+	mu_pop_clip_rect(ctx);
+	pop_container(ctx);
 }
 
 
-int mu_begin_window_ex(mu_Context *ctx, mu_Container *cnt, const char *title,
-  int opt)
+int
+mu_begin_window_ex(mu_Context *ctx, mu_Container *cnt, const char *title, int opt)
 {
-  mu_Rect rect, body, titlerect;
+	mu_Rect rect, body, titlerect;
 
-  if (!cnt->inited) { mu_init_window(ctx, cnt, opt); }
-  if (!cnt->open) { return 0; }
+	if (!cnt->inited)
+		mu_init_window(ctx, cnt, opt);
+	if (!cnt->open)
+		return 0;
 
-  begin_root_container(ctx, cnt);
-  rect = cnt->rect;
-  body = rect;
+	begin_root_container(ctx, cnt);
+	rect = cnt->rect;
+	body = rect;
 
-  /* draw frame */
-  if (~opt & MU_OPT_NOFRAME) {
-    draw_frame(ctx, rect, MU_COLOR_WINDOWBG);
-  }
+	/* draw frame */
+	if (~opt & MU_OPT_NOFRAME)
+		draw_frame(ctx, rect, MU_COLOR_WINDOWBG);
 
-  /* do title bar */
-  titlerect = rect;
-  titlerect.h = ctx->style->title_height;
-  if (~opt & MU_OPT_NOTITLE) {
-    draw_frame(ctx, titlerect, MU_COLOR_TITLEBG);
+	/* do title bar */
+	titlerect = rect;
+	titlerect.h = ctx->style->title_height;
+	if (~opt & MU_OPT_NOTITLE) {
+		draw_frame(ctx, titlerect, MU_COLOR_TITLEBG);
 
-    /* do title text */
-    if (~opt & MU_OPT_NOTITLE) {
-      mu_Id id = mu_get_id(ctx, "!title", 6);
-      mu_update_control(ctx, id, titlerect, opt);
-      mu_draw_control_text(ctx, title, titlerect, MU_COLOR_TITLETEXT, opt);
-      if (id == ctx->focus && ctx->mouse_down == MU_MOUSE_LEFT) {
-        cnt->rect.x += ctx->mouse_delta.x;
-        cnt->rect.y += ctx->mouse_delta.y;
-      }
-      body.y += titlerect.h;
-      body.h -= titlerect.h;
-    }
+		/* do title text */
+		if (~opt & MU_OPT_NOTITLE) {
+			mu_Id id = mu_get_id(ctx, "!title", 6);
+			mu_update_control(ctx, id, titlerect, opt);
+			mu_draw_control_text(ctx, title, titlerect, MU_COLOR_TITLETEXT, opt);
+			if (id == ctx->focus && ctx->mouse_down == MU_MOUSE_LEFT) {
+				cnt->rect.x += ctx->mouse_delta.x;
+				cnt->rect.y += ctx->mouse_delta.y;
+			}
+			body.y += titlerect.h;
+			body.h -= titlerect.h;
+		}
 
-    /* do `close` button */
-    if (~opt & MU_OPT_NOCLOSE) {
-      mu_Id id = mu_get_id(ctx, "!close", 6);
-      mu_Rect r = mu_rect(
-        titlerect.x + titlerect.w - titlerect.h,
-        titlerect.y, titlerect.h, titlerect.h);
-      titlerect.w -= r.w;
-      mu_draw_icon(ctx, MU_ICON_CLOSE, r);
-      mu_update_control(ctx, id, r, opt);
-      if (ctx->mouse_pressed == MU_MOUSE_LEFT && id == ctx->focus) {
-        cnt->open = 0;
-      }
-    }
-  }
+		/* do `close` button */
+		if (~opt & MU_OPT_NOCLOSE) {
+			mu_Id id = mu_get_id(ctx, "!close", 6);
+			mu_Rect r = mu_rect(
+				titlerect.x + titlerect.w - titlerect.h,
+				titlerect.y, titlerect.h, titlerect.h
+			);
+			titlerect.w -= r.w;
+			mu_draw_icon(ctx, MU_ICON_CLOSE, r);
+			mu_update_control(ctx, id, r, opt);
+			if (ctx->mouse_pressed == MU_MOUSE_LEFT && id == ctx->focus)
+				cnt->open = 0;
+		}
+	}
 
-  push_container_body(ctx, cnt, body, opt);
+	push_container_body(ctx, cnt, body, opt);
 
-  /* do `resize` handle */
-  if (~opt & MU_OPT_NORESIZE) {
-    int sz = ctx->style->scrollbar_size;
-    mu_Id id = mu_get_id(ctx, "!resize", 7);
-    mu_Rect r = mu_rect(rect.x + rect.w - sz, rect.y + rect.h - sz, sz, sz);
-    mu_update_control(ctx, id, r, opt);
-    if (id == ctx->focus && ctx->mouse_down == MU_MOUSE_LEFT) {
-      cnt->rect.w = mu_max(96, cnt->rect.w + ctx->mouse_delta.x);
-      cnt->rect.h = mu_max(64, cnt->rect.h + ctx->mouse_delta.y);
-    }
-  }
+	/* do `resize` handle */
+	if (~opt & MU_OPT_NORESIZE) {
+		int sz = ctx->style->scrollbar_size;
+		mu_Id id = mu_get_id(ctx, "!resize", 7);
+		mu_Rect r = mu_rect(rect.x + rect.w - sz, rect.y + rect.h - sz, sz, sz);
+		mu_update_control(ctx, id, r, opt);
+		if (id == ctx->focus && ctx->mouse_down == MU_MOUSE_LEFT) {
+			cnt->rect.w = max(96, cnt->rect.w + ctx->mouse_delta.x);
+			cnt->rect.h = max(64, cnt->rect.h + ctx->mouse_delta.y);
+		}
+	}
 
-  /* resize to content size */
-  if (opt & MU_OPT_AUTOSIZE) {
-    mu_Rect r = get_layout(ctx)->body;
-    cnt->rect.w = cnt->content_size.x + (cnt->rect.w - r.w);
-    cnt->rect.h = cnt->content_size.y + (cnt->rect.h - r.h);
-  }
+	/* resize to content size */
+	if (opt & MU_OPT_AUTOSIZE) {
+		mu_Rect r = get_layout(ctx)->body;
+		cnt->rect.w = cnt->content_size.x + (cnt->rect.w - r.w);
+		cnt->rect.h = cnt->content_size.y + (cnt->rect.h - r.h);
+	}
 
-  /* close if this is a popup window and elsewhere was clicked */
-  if (opt & MU_OPT_POPUP && ctx->mouse_pressed && ctx->last_hover_root != cnt) {
-    cnt->open = 0;
-  }
+	/* close if this is a popup window and elsewhere was clicked */
+	if (opt & MU_OPT_POPUP && ctx->mouse_pressed && ctx->last_hover_root != cnt)
+		cnt->open = 0;
 
-  mu_push_clip_rect(ctx, cnt->body);
-  return MU_RES_ACTIVE;
+	mu_push_clip_rect(ctx, cnt->body);
+	return MU_RES_ACTIVE;
 }
 
 
-int mu_begin_window(mu_Context *ctx, mu_Container *cnt, const char *title) {
-  return mu_begin_window_ex(ctx, cnt, title, 0);
+int
+mu_begin_window(mu_Context *ctx, mu_Container *cnt, const char *title)
+{
+	return mu_begin_window_ex(ctx, cnt, title, 0);
 }
 
 
-void mu_end_window(mu_Context *ctx) {
-  mu_pop_clip_rect(ctx);
-  end_root_container(ctx);
+void
+mu_end_window(mu_Context *ctx)
+{
+	mu_pop_clip_rect(ctx);
+	end_root_container(ctx);
 }
 
 
-void mu_open_popup(mu_Context *ctx, mu_Container *cnt) {
-  /* set as hover root so popup isn't closed in begin_window_ex()  */
-  ctx->last_hover_root = ctx->hover_root = cnt;
-  /* init container if not inited */
-  if (!cnt->inited) { mu_init_window(ctx, cnt, 0); }
-  /* position at mouse cursor, open and bring-to-front */
-  cnt->rect = mu_rect(ctx->mouse_pos.x, ctx->mouse_pos.y, 0, 0);
-  cnt->open = 1;
-  mu_bring_to_front(ctx, cnt);
+void
+mu_open_popup(mu_Context *ctx, mu_Container *cnt)
+{
+	/* set as hover root so popup isn't closed in begin_window_ex() */
+	ctx->last_hover_root = ctx->hover_root = cnt;
+	/* init container if not inited */
+	if (!cnt->inited)
+		mu_init_window(ctx, cnt, 0);
+	/* position at mouse cursor, open and bring-to-front */
+	cnt->rect = mu_rect(ctx->mouse_pos.x, ctx->mouse_pos.y, 0, 0);
+	cnt->open = 1;
+	mu_bring_to_front(ctx, cnt);
 }
 
 
-int mu_begin_popup(mu_Context *ctx, mu_Container *cnt) {
-  int opt = MU_OPT_POPUP | MU_OPT_AUTOSIZE | MU_OPT_NORESIZE |
-            MU_OPT_NOSCROLL | MU_OPT_NOTITLE | MU_OPT_CLOSED;
-  return mu_begin_window_ex(ctx, cnt, "", opt);
+int
+mu_begin_popup(mu_Context *ctx, mu_Container *cnt)
+{
+	return mu_begin_window_ex(
+		ctx,
+		cnt,
+		"",
+		MU_OPT_POPUP | MU_OPT_AUTOSIZE | MU_OPT_NORESIZE | MU_OPT_NOSCROLL | MU_OPT_NOTITLE | MU_OPT_CLOSED
+	);
 }
 
 
-void mu_end_popup(mu_Context *ctx) {
-  mu_end_window(ctx);
+void
+mu_end_popup(mu_Context *ctx)
+{
+	mu_end_window(ctx);
 }
 
 
-void mu_begin_panel_ex(mu_Context *ctx, mu_Container *cnt, int opt) {
-  cnt->rect = mu_layout_next(ctx);
-  if (~opt & MU_OPT_NOFRAME) {
-    draw_frame(ctx, cnt->rect, MU_COLOR_PANELBG);
-  }
-  push_container(ctx, cnt);
-  push_container_body(ctx, cnt, cnt->rect, opt);
-  mu_push_clip_rect(ctx, cnt->body);
+void
+mu_begin_panel_ex(mu_Context *ctx, mu_Container *cnt, int opt)
+{
+	cnt->rect = mu_layout_next(ctx);
+	if (~opt & MU_OPT_NOFRAME)
+		draw_frame(ctx, cnt->rect, MU_COLOR_PANELBG);
+
+	push_container(ctx, cnt);
+	push_container_body(ctx, cnt, cnt->rect, opt);
+	mu_push_clip_rect(ctx, cnt->body);
 }
 
 
-void mu_begin_panel(mu_Context *ctx, mu_Container *cnt) {
-  mu_begin_panel_ex(ctx, cnt, 0);
+void
+mu_begin_panel(mu_Context *ctx, mu_Container *cnt)
+{
+	mu_begin_panel_ex(ctx, cnt, 0);
 }
 
 
-void mu_end_panel(mu_Context *ctx) {
-  mu_pop_clip_rect(ctx);
-  pop_container(ctx);
+void
+mu_end_panel(mu_Context *ctx)
+{
+	mu_pop_clip_rect(ctx);
+	pop_container(ctx);
 }
 
 int
@@ -1265,23 +1408,27 @@
 mu_render(mu_Context *ctx)
 {
 	mu_Command *cmd;
-	mu_Rect r, i;
+	mu_Rect r, iconr;
 
 	if (memcmp(&ctx->screen, &screen->r, sizeof(ctx->screen)) != 0)
 		ctx->screen = screen->r;
-	else if (ctx->old_command_list.idx == ctx->command_list.idx && memcmp(ctx->old_command_list.items, ctx->command_list.items, ctx->command_list.idx) == 0)
+	else if (ctx->oldcmdsnum == ctx->cmdsnum && memcmp(ctx->oldcmds, ctx->cmds, ctx->cmdsnum*sizeof(mu_Command)) == 0)
 		return 0;
 
-	ctx->old_command_list.idx = ctx->command_list.idx;
-	memmove(ctx->old_command_list.items, ctx->command_list.items, ctx->command_list.idx);
-	cmd = nil;
+	if (ctx->oldcmdsmax != ctx->cmdsmax && (ctx->oldcmds = realloc(ctx->oldcmds, ctx->cmdsmax*sizeof(mu_Command))) == nil)
+		sysfatal("couldn't allocate memory for old cmds");
+	ctx->oldcmdsmax = ctx->cmdsmax;
+	ctx->oldcmdsnum = ctx->cmdsnum;
+	memmove(ctx->oldcmds, ctx->cmds, ctx->cmdsnum*sizeof(mu_Command));
+
 	if (ctx->style->colors[MU_COLOR_BG] != nil)
 		draw(screen, screen->r, ctx->style->colors[MU_COLOR_BG], nil, ZP);
-	while (mu_next_command(ctx, &cmd)) {
+
+	for (cmd = ctx->cmds; cmd < ctx->cmds + ctx->cmdsnum;) {
 		switch (cmd->type) {
 		case MU_COMMAND_TEXT:
 			if (cmd->text.color != nil)
-				string(screen, addpt(screen->r.min, cmd->text.pos), cmd->text.color, ZP, ctx->style->font, cmd->text.str);
+				string(screen, addpt(screen->r.min, cmd->text.pos), cmd->text.color, ZP, ctx->style->font, ctx->str+cmd->text.s);
 			break;
 
 		case MU_COMMAND_RECT:
@@ -1291,19 +1438,27 @@
 
 		case MU_COMMAND_ICON:
 			r = cmd->icon.rect;
-			i = atlasicons[cmd->icon.id];
-			r.x += (r.w - i.w) / 2;
-			r.y += (r.h - i.h) / 2;
-			r.w = i.w;
-			r.h = i.h;
-			draw(screen, screenrect(r), atlasimage, nil, Pt(i.x, i.y));
+			iconr = atlasicons[cmd->icon.id];
+			r.x += (r.w - iconr.w) / 2;
+			r.y += (r.h - iconr.h) / 2;
+			r.w = iconr.w;
+			r.h = iconr.h;
+			draw(screen, screenrect(r), atlasimage, nil, Pt(iconr.x, iconr.y));
 			break;
 
 		case MU_COMMAND_CLIP:
 			replclipr(screen, 0, screenrect(cmd->clip.rect));
 			break;
+
+		case MU_COMMAND_JUMP:
+			if (cmd->jump.dst < 0)
+				return 1;
+			cmd = &ctx->cmds[cmd->jump.dst];
+			continue;
 		}
+
+		cmd++;
 	}
 
-	return  1;
+	return 1;
 }
--- a/microui.h
+++ b/microui.h
@@ -1,199 +1,248 @@
 #pragma lib "libmicroui.a"
 
-#define MU_COMMANDLIST_SIZE     (1024 * 256)
-#define MU_ROOTLIST_SIZE        32
-#define MU_CONTAINERSTACK_SIZE  32
-#define MU_CLIPSTACK_SIZE       32
-#define MU_IDSTACK_SIZE         32
-#define MU_LAYOUTSTACK_SIZE     16
-#define MU_MAX_WIDTHS           16
-#define MU_REAL_FMT             "%.3g"
-#define MU_SLIDER_FMT           "%.2f"
-#define MU_MAX_FMT              127
+typedef unsigned mu_Id;
 
-#define mu_stack(T, n)          struct { int idx; T items[n]; }
-#define mu_min(a, b)            ((a) < (b) ? (a) : (b))
-#define mu_max(a, b)            ((a) > (b) ? (a) : (b))
-#define mu_clamp(x, a, b)       mu_min(b, mu_max(a, x))
+typedef struct mu_Command mu_Command;
+typedef struct mu_Container mu_Container;
+typedef struct mu_Context mu_Context;
+typedef struct mu_Layout mu_Layout;
+typedef struct mu_Style mu_Style;
+typedef struct mu_Rect mu_Rect;
 
-enum {
-  MU_CLIP_NONE,
-  MU_CLIP_PART,
-  MU_CLIP_ALL
+enum
+{
+	MU_MAX_WIDTHS	= 16,
+	MU_MAX_FMT		= 127,
 };
 
-enum {
-  MU_COMMAND_JUMP = 1,
-  MU_COMMAND_CLIP,
-  MU_COMMAND_RECT,
-  MU_COMMAND_TEXT,
-  MU_COMMAND_ICON,
-  MU_COMMAND_MAX
+#define MU_REAL_FMT   "%.3g"
+#define MU_SLIDER_FMT "%.2f"
+
+enum
+{
+	MU_CLIP_NONE,
+	MU_CLIP_PART,
+	MU_CLIP_ALL,
 };
 
-enum {
-  MU_COLOR_BG,
-  MU_COLOR_TEXT,
-  MU_COLOR_BORDER,
-  MU_COLOR_WINDOWBG,
-  MU_COLOR_TITLEBG,
-  MU_COLOR_TITLETEXT,
-  MU_COLOR_PANELBG,
-  MU_COLOR_BUTTON,
-  MU_COLOR_BUTTONHOVER,
-  MU_COLOR_BUTTONFOCUS,
-  MU_COLOR_BASE,
-  MU_COLOR_BASEHOVER,
-  MU_COLOR_BASEFOCUS,
-  MU_COLOR_SCROLLBASE,
-  MU_COLOR_SCROLLTHUMB,
-  MU_COLOR_MAX
+enum
+{
+	MU_COMMAND_JUMP,
+	MU_COMMAND_CLIP,
+	MU_COMMAND_RECT,
+	MU_COMMAND_TEXT,
+	MU_COMMAND_ICON,
+	MU_COMMAND_MAX,
 };
 
-enum {
+enum
+{
+	MU_COLOR_BG,
+	MU_COLOR_TEXT,
+	MU_COLOR_BORDER,
+	MU_COLOR_WINDOWBG,
+	MU_COLOR_TITLEBG,
+	MU_COLOR_TITLETEXT,
+	MU_COLOR_PANELBG,
+	MU_COLOR_BUTTON,
+	MU_COLOR_BUTTONHOVER,
+	MU_COLOR_BUTTONFOCUS,
+	MU_COLOR_BASE,
+	MU_COLOR_BASEHOVER,
+	MU_COLOR_BASEFOCUS,
+	MU_COLOR_SCROLLBASE,
+	MU_COLOR_SCROLLTHUMB,
+	MU_COLOR_MAX,
+};
+
+enum
+{
 	MU_ICON_CHECK,
 	MU_ICON_CLOSE,
 	MU_ICON_COLLAPSED,
 	MU_ICON_EXPANDED,
+	MU_ICON_RESIZE,
 	ATLAS_DIMENSIONS,
 };
 
-enum {
-  MU_RES_ACTIVE       = (1 << 0),
-  MU_RES_SUBMIT       = (1 << 1),
-  MU_RES_CHANGE       = (1 << 2)
+enum
+{
+	MU_RES_ACTIVE	= 1<<0,
+	MU_RES_SUBMIT	= 1<<1,
+	MU_RES_CHANGE	= 1<<2
 };
 
-enum {
-  MU_OPT_ALIGNCENTER  = (1 << 0),
-  MU_OPT_ALIGNRIGHT   = (1 << 1),
-  MU_OPT_NOINTERACT   = (1 << 2),
-  MU_OPT_NOFRAME      = (1 << 3),
-  MU_OPT_NORESIZE     = (1 << 4),
-  MU_OPT_NOSCROLL     = (1 << 5),
-  MU_OPT_NOCLOSE      = (1 << 6),
-  MU_OPT_NOTITLE      = (1 << 7),
-  MU_OPT_HOLDFOCUS    = (1 << 8),
-  MU_OPT_AUTOSIZE     = (1 << 9),
-  MU_OPT_POPUP        = (1 << 10),
-  MU_OPT_CLOSED       = (1 << 11)
+enum
+{
+	MU_OPT_ALIGNCENTER	= 1<<0,
+	MU_OPT_ALIGNRIGHT	= 1<<1,
+	MU_OPT_NOINTERACT	= 1<<2,
+	MU_OPT_NOFRAME		= 1<<3,
+	MU_OPT_NORESIZE		= 1<<4,
+	MU_OPT_NOSCROLL		= 1<<5,
+	MU_OPT_NOCLOSE		= 1<<6,
+	MU_OPT_NOTITLE		= 1<<7,
+	MU_OPT_HOLDFOCUS	= 1<<8,
+	MU_OPT_AUTOSIZE		= 1<<9,
+	MU_OPT_POPUP		= 1<<10,
+	MU_OPT_CLOSED		= 1<<11,
 };
 
-enum {
-  MU_MOUSE_LEFT       = (1 << 0),
-  MU_MOUSE_RIGHT      = (1 << 1),
-  MU_MOUSE_MIDDLE     = (1 << 2)
+enum
+{
+	MU_MOUSE_LEFT	= 1<<0,
+	MU_MOUSE_RIGHT	= 1<<1,
+	MU_MOUSE_MIDDLE	= 1<<2,
 };
 
-enum {
-  MU_KEY_SHIFT        = (1 << 0),
-  MU_KEY_CTRL         = (1 << 1),
-  MU_KEY_ALT          = (1 << 2),
-  MU_KEY_BACKSPACE    = (1 << 3),
-  MU_KEY_RETURN       = (1 << 4),
-  MU_KEY_NACK         = (1 << 5),
-  MU_KEY_LEFT         = (1 << 6),
-  MU_KEY_RIGHT        = (1 << 7),
+enum
+{
+	MU_KEY_SHIFT		= 1<<0,
+	MU_KEY_CTRL			= 1<<1,
+	MU_KEY_ALT			= 1<<2,
+	MU_KEY_BACKSPACE	= 1<<3,
+	MU_KEY_RETURN		= 1<<4,
+	MU_KEY_NACK			= 1<<5,
+	MU_KEY_LEFT			= 1<<6,
+	MU_KEY_RIGHT		= 1<<7,
 };
 
+struct mu_Rect
+{
+	int x;
+	int y;
+	int w;
+	int h;
+};
 
-typedef struct mu_Context mu_Context;
-typedef unsigned mu_Id;
+struct mu_Command
+{
+	int type;
 
-typedef struct { int x, y, w, h; } mu_Rect;
+	union
+	{
+		struct
+		{
+			int dst;
+		}jump;
 
-typedef struct { int type, size; } mu_BaseCommand;
-typedef struct { mu_BaseCommand base; void *dst; } mu_JumpCommand;
-typedef struct { mu_BaseCommand base; mu_Rect rect; } mu_ClipCommand;
-typedef struct { mu_BaseCommand base; mu_Rect rect; Image *color; } mu_RectCommand;
-typedef struct { mu_BaseCommand base; Font *font; Point pos; Image *color; char str[1]; } mu_TextCommand;
-typedef struct { mu_BaseCommand base; mu_Rect rect; int id; } mu_IconCommand;
+		struct
+		{
+			mu_Rect rect;
+		}clip;
 
-typedef union {
-  int type;
-  mu_BaseCommand base;
-  mu_JumpCommand jump;
-  mu_ClipCommand clip;
-  mu_RectCommand rect;
-  mu_TextCommand text;
-  mu_IconCommand icon;
-} mu_Command;
+		struct
+		{
+			Image *color;
+			mu_Rect rect;
+		}rect;
 
+		struct
+		{
+			Font *font;
+			Image *color;
+			int s;
+			Point pos;
+		}text;
 
-typedef struct {
-  mu_Rect body;
-  mu_Rect next;
-  Point position;
-  Point size;
-  Point max;
-  int widths[MU_MAX_WIDTHS];
-  int items;
-  int row_index;
-  int next_row;
-  int next_type;
-  int indent;
-} mu_Layout;
+		struct
+		{
+			mu_Rect rect;
+			int id;
+		}icon;
+	};
+};
 
+struct mu_Layout
+{
+	mu_Rect body;
+	mu_Rect next;
+	Point position;
+	Point size;
+	Point max;
+	int widths[MU_MAX_WIDTHS];
+	int items;
+	int row_index;
+	int next_row;
+	int next_type;
+	int indent;
+};
 
-typedef struct {
-  mu_Command *head, *tail;
-  mu_Rect rect;
-  mu_Rect body;
-  Point content_size;
-  Point scroll;
-  int inited;
-  int zindex;
-  int open;
-} mu_Container;
+struct mu_Container
+{
+	int head, tail;
+	mu_Rect rect;
+	mu_Rect body;
+	Point content_size;
+	Point scroll;
+	int inited;
+	int zindex;
+	int open;
+};
 
+struct mu_Style
+{
+	Font *font;
+	Point size;
+	int padding;
+	int spacing;
+	int indent;
+	int title_height;
+	int scrollbar_size;
+	int thumb_size;
+	Image *colors[MU_COLOR_MAX];
+};
 
-typedef struct {
-  Font *font;
-  Point size;
-  int padding;
-  int spacing;
-  int indent;
-  int title_height;
-  int scrollbar_size;
-  int thumb_size;
-  Image *colors[MU_COLOR_MAX];
-} mu_Style;
+struct mu_Context
+{
+	/* core state */
+	mu_Style _style;
+	mu_Style *style;
+	mu_Id hover;
+	mu_Id focus;
+	mu_Id last_id;
+	mu_Rect last_rect;
+	int last_zindex;
+	int updated_focus;
+	mu_Container *hover_root;
+	mu_Container *last_hover_root;
+	mu_Container *scroll_target;
+	char number_buf[MU_MAX_FMT];
+	mu_Id number_editing;
+	Rectangle screen;
 
+	/* buffers */
+	char *str;
+	int strmax, strnum;
 
-struct mu_Context {
-  /* core state */
-  mu_Style _style;
-  mu_Style *style;
-  mu_Id hover;
-  mu_Id focus;
-  mu_Id last_id;
-  mu_Rect last_rect;
-  int last_zindex;
-  int updated_focus;
-  mu_Container *hover_root;
-  mu_Container *last_hover_root;
-  mu_Container *scroll_target;
-  char number_buf[MU_MAX_FMT];
-  mu_Id number_editing;
-  Rectangle screen;
-  /* stacks */
-  mu_stack(char, MU_COMMANDLIST_SIZE) command_list;
-  mu_stack(char, MU_COMMANDLIST_SIZE) old_command_list;
-  mu_stack(mu_Container*, MU_ROOTLIST_SIZE) root_list;
-  mu_stack(mu_Container*, MU_CONTAINERSTACK_SIZE) container_stack;
-  mu_stack(mu_Rect, MU_CLIPSTACK_SIZE) clip_stack;
-  mu_stack(mu_Id, MU_IDSTACK_SIZE) id_stack;
-  mu_stack(mu_Layout, MU_LAYOUTSTACK_SIZE) layout_stack;
-  /* input state */
-  Point mouse_pos;
-  Point last_mouse_pos;
-  Point mouse_delta;
-  Point scroll_delta;
-  int mouse_down;
-  int mouse_pressed;
-  int key_down;
-  int key_pressed;
-  char text_input[32];
+	mu_Container **root;
+	int rootmax, rootnum;
+
+	mu_Container **cnt;
+	int cntmax, cntnum;
+
+	mu_Rect *clip;
+	int clipmax, clipnum;
+
+	mu_Id *ids;
+	int idsmax, idsnum;
+
+	mu_Layout *layouts;
+	int layoutsmax, layoutsnum;
+
+	mu_Command *cmds, *oldcmds;
+	int cmdsmax, cmdsnum, oldcmdsmax, oldcmdsnum;
+
+	/* input state */
+	Point mouse_pos;
+	Point last_mouse_pos;
+	Point mouse_delta;
+	Point scroll_delta;
+	int mouse_down;
+	int mouse_pressed;
+	int key_down;
+	int key_pressed;
+	char text_input[64];
 };
 
 extern Image *atlasimage;
@@ -227,8 +276,7 @@
 void mu_input_keyup(mu_Context *ctx, int key);
 void mu_input_text(mu_Context *ctx, const char *text);
 
-mu_Command* mu_push_command(mu_Context *ctx, int type, int size);
-int mu_next_command(mu_Context *ctx, mu_Command **cmd);
+mu_Command *mu_push_command(mu_Context *ctx, int type);
 void mu_set_clip(mu_Context *ctx, mu_Rect rect);
 void mu_draw_rect(mu_Context *ctx, mu_Rect rect, Image *color);
 void mu_draw_box(mu_Context *ctx, mu_Rect rect, Image *color);