diff --git a/roo-e/src/gui/widgets/button.c b/roo-e/src/gui/widgets/button.c
new file mode 100644
index 0000000..f376866
--- /dev/null
+++ b/roo-e/src/gui/widgets/button.c
@@ -0,0 +1,134 @@
+/*
+ * Roo/E, the Kangaroo Punch Portable GUI Toolkit
+ * Copyright (C) 2022 Scott Duensing
+ *
+ * http://kangaroopunch.com
+ *
+ *
+ * This file is part of Roo/E.
+ *
+ * Roo/E is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * Roo/E is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Roo/E. If not, see .
+ *
+ */
+
+
+#include "../wmwindow.h"
+
+#include "button.h"
+
+
+uint8_t __MAGIC_BUTTON = 0;
+
+
+static void buttonClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
+static void buttonDestroy(struct WidgetS *widget, ...);
+static void buttonPaint(struct WidgetS *widget, ...);
+
+
+static void buttonClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
+ ButtonT *b = (ButtonT *)widget;
+
+ switch (event) {
+ case CLICK_LEFT_DOWN:
+ b->isPressed = 1;
+ break;
+
+ case CLICK_LEFT_UP:
+ b->isPressed = 0;
+ // Call the actual click event.
+ b->handler(widget, x, y, event, data);
+ break;
+
+ case CLICK_LEFT_CANCEL:
+ b->isPressed = 0;
+ break;
+ }
+
+ guiWidgetDirtySet(widget, 1);
+}
+
+
+void buttonClickSet(ButtonT *button, ClickHandlerT handler, void *data) {
+ button->handler = handler;
+ button->base.data = data;
+}
+
+
+ButtonT *buttonCreate(char *label, ClickHandlerT handler, void *data, ...) {
+ ButtonT *b = NULL;
+ uint16_t width;
+ uint16_t height;
+ FontT *f = __guiFontVGA8x16;
+
+ NEW(ButtonT, b);
+ memset(b, 0, sizeof(ButtonT));
+
+ b->offset.x = 8; // 8 = two border, 6 padding.
+ b->offset.y = 4; // 4 = two border, two padding.
+ b->label = labelCreate(LABEL_ALIGN_LEFT, f, label);
+ if (!b->label) {
+ DEL(b);
+ return NULL;
+ }
+
+ width = fontWidthCharactersGet(label) * fontWidthGet(f) + (b->offset.x * 2);
+ height = fontHeightGet(f) + (b->offset.y * 2);
+
+ guiWidgetBaseSet(W(b), __MAGIC_BUTTON, width, height);
+
+ buttonClickSet(b, handler, data);
+
+ return b;
+}
+
+
+static void buttonDestroy(struct WidgetS *widget, ...) {
+ ButtonT *b = (ButtonT *)widget;
+
+ guiWidgetDestroy(W(b->label));
+ DEL(b);
+}
+
+
+static void buttonPaint(struct WidgetS *widget, ...) {
+ ButtonT *b = (ButtonT *)widget;
+ ColorT h = b->isPressed ? GUI_BLACK : GUI_WHITE;
+ ColorT s = b->isPressed ? GUI_WHITE : GUI_BLACK;
+
+ if (guiWidgetDirtyGet(widget)) {
+ guiWidgetDirtySet(widget, 0);
+ // Paint button.
+ surfaceBoxHighlight(b->base.r.x, b->base.r.y, b->base.r.x + b->base.r.x2 - 1, b->base.r.y + b->base.r.y2 - 1, h, s);
+ surfaceBoxHighlight(b->base.r.x + 1, b->base.r.y + 1, b->base.r.x + b->base.r.x2 - 2, b->base.r.y + b->base.r.y2 - 2, h, s);
+ surfaceBoxFilled(b->base.r.x + 2, b->base.r.y + 2, b->base.r.x + b->base.r.x2 - 3, b->base.r.y + b->base.r.y2 - 3, GUI_LIGHTGRAY);
+ // Paint label.
+ guiWidgetPaintManually(W(b->label), b->base.r.x + b->offset.x + b->isPressed, b->base.r.y + b->offset.y + b->isPressed);
+ }
+}
+
+
+RegisterT *buttonRegister(uint8_t magic) {
+ static RegisterT reg = {
+ "Button",
+ buttonClick,
+ buttonDestroy,
+ buttonPaint,
+ NULL // No unregister handler.
+ };
+
+ // One-time widget startup code.
+ __MAGIC_BUTTON = magic;
+
+ return ®
+}
diff --git a/roo-e/src/gui/widgets/button.h b/roo-e/src/gui/widgets/button.h
new file mode 100644
index 0000000..de52041
--- /dev/null
+++ b/roo-e/src/gui/widgets/button.h
@@ -0,0 +1,51 @@
+/*
+ * Roo/E, the Kangaroo Punch Portable GUI Toolkit
+ * Copyright (C) 2022 Scott Duensing
+ *
+ * http://kangaroopunch.com
+ *
+ *
+ * This file is part of Roo/E.
+ *
+ * Roo/E is free software: you can redistribute it and/or modify it under the
+ * terms of the GNU Affero General Public License as published by the Free
+ * Software Foundation, either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * Roo/E is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with Roo/E. If not, see .
+ *
+ */
+
+
+#ifndef BUTTON_H
+#define BUTTON_H
+
+
+#include "../gui.h"
+#include "label.h"
+
+
+typedef struct ButtonS {
+ WidgetT base; // Required by all widgets.
+ LabelT *label; // Label to display text.
+ PointT offset; // Offset of label in button.
+ ClickHandlerT handler; // Actual event handler.
+ uint8_t isPressed; // Is the button being pressed?
+} ButtonT;
+
+
+extern uint8_t __MAGIC_BUTTON; // Magic ID assigned to us from the GUI.
+
+
+void buttonClickSet(ButtonT *button, ClickHandlerT handler, void *data);
+ButtonT *buttonCreate(char *label, ClickHandlerT handler, void *data, ...);
+RegisterT *buttonRegister(uint8_t magic);
+
+
+#endif // BUTTON_H