packages feed

bearlibterminal (empty) → 0.1.0.0

raw patch · 16 files changed

+2729/−0 lines, 16 filesdep +basedep +bearlibterminaldep +bytestring

Dependencies added: base, bearlibterminal, bytestring, containers, formatting, mtl, random, text, time, vector, word8

Files

+ bearlibterminal.cabal view
@@ -0,0 +1,86 @@+cabal-version: 3.6+name:          bearlibterminal+version:       0.1.0.0+synopsis:      Low-level Haskell bindings to the BearLibTerminal graphics library.+description:+  A Haskell wrapper for a graphics library for making roguelike-style games.+  From the [BearLibTerminal documentation](http://foo.wyrd.name/en:bearlibterminal):+    BearLibTerminal is a library that creates a terminal-like window facilitating flexible textual output and uncomplicated input processing.+    A lot of roguelike games intentionally use aesthetic textual or pseudographic visual style. However, native output via the command line+    interface usually has a few annoying shortcomings such as low speed or palette and font restrictions.+    Using an extended character set (several languages at once or complicated pseudographics) may also be tricky. BearLibTerminal solves+    that by providing its own window with a grid of character cells and simple yet powerful API for configuration and textual output.++homepage:      https://github.com/PPKFS/bearlibterminal-hs+bug-reports:   https://github.com/PPKFS/bearlibterminal-hs/issues+license:       MIT+author:        Avery+maintainer:    Avery <ppkfs@outlook.com>+copyright:     2024-2025 Avery+category:      Game Development+build-type:    Simple+tested-with:   GHC == 9.8.2++source-repository head+  type:     git+  location: https://github.com/PPKFS/bearlibterminal-hs.git++common common-options+  build-depends:+      base >= 4.17.2 && < 5+    , text >= 2.1.1 && < 3+    , bytestring >= 0.12.1 && < 2+    , mtl >= 2.3.1 && < 3++  ghc-options:+    -Wall -Wcompat -Widentities -Wredundant-constraints+    -Wno-unused-packages -Wno-deprecations -fhide-source-paths+    -Wno-unused-top-binds -Wmissing-deriving-strategies++  default-language: GHC2021+  default-extensions:+    DerivingStrategies+    OverloadedStrings+    MultiWayIf+    BlockArguments+    LambdaCase++library+  import: common-options+  hs-source-dirs:  src+  exposed-modules:+    BearLibTerminal+    BearLibTerminal.Raw+    BearLibTerminal.Keycodes+    BearLibTerminal.Terminal.CString+    BearLibTerminal.Terminal.Color+    BearLibTerminal.Terminal.Print+    BearLibTerminal.Terminal.Set+    BearLibTerminal.Terminal.String+  extra-libraries: stdc++ BearLibTerminal+  include-dirs:+    cbits+  includes:+    cbits/BearLibTerminal.h+    cbits/BearLibTerminalExtras.h+  install-includes:+    cbits/BearLibTerminal.h+    cbits/BearLibTerminalExtras.h++executable omni+  import: common-options+  build-depends:+    bearlibterminal >= 0.1.0.0 && <= 0.2.0.0,+    containers >= 0.6.8 && < 1,+    formatting >= 7.2.0 && < 8,+    time >= 1.12.2 && < 2,+    random >= 1.3.0 && < 2,+    vector >= 0.13.2 && < 1,+    word8 >= 0.1.3 && < 1,+  hs-source-dirs:  omni+  main-is: Main.hs+  other-modules:+    Omni.BasicOutput+    Omni.DefaultFont+    Omni.Tilesets+    Omni.ManualCellsize
+ cbits/BearLibTerminal.h view
@@ -0,0 +1,766 @@+/*
+* BearLibTerminal
+* Copyright (C) 2013-2017 Cfyz
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to deal
+* in the Software without restriction, including without limitation the rights
+* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+* of the Software, and to permit persons to whom the Software is furnished to do
+* so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all
+* copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef BEARLIBTERMINAL_H
+#define BEARLIBTERMINAL_H
+
+#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#ifdef __GNUC__
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 1)
+#pragma GCC diagnostic ignored "-Wformat-nonliteral" /* False-positive when wrapping vsnprintf. */
+#endif /* __GNUC__ >= 4.1 */
+#endif
+
+#include <stdio.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <wchar.h>
+#if defined(__cplusplus)
+#include <sstream>
+#endif
+
+/*
+ * Keyboard scancodes for events/states
+ */
+#define TK_A                0x04
+#define TK_B                0x05
+#define TK_C                0x06
+#define TK_D                0x07
+#define TK_E                0x08
+#define TK_F                0x09
+#define TK_G                0x0A
+#define TK_H                0x0B
+#define TK_I                0x0C
+#define TK_J                0x0D
+#define TK_K                0x0E
+#define TK_L                0x0F
+#define TK_M                0x10
+#define TK_N                0x11
+#define TK_O                0x12
+#define TK_P                0x13
+#define TK_Q                0x14
+#define TK_R                0x15
+#define TK_S                0x16
+#define TK_T                0x17
+#define TK_U                0x18
+#define TK_V                0x19
+#define TK_W                0x1A
+#define TK_X                0x1B
+#define TK_Y                0x1C
+#define TK_Z                0x1D
+#define TK_1                0x1E
+#define TK_2                0x1F
+#define TK_3                0x20
+#define TK_4                0x21
+#define TK_5                0x22
+#define TK_6                0x23
+#define TK_7                0x24
+#define TK_8                0x25
+#define TK_9                0x26
+#define TK_0                0x27
+#define TK_RETURN           0x28
+#define TK_ENTER            0x28
+#define TK_ESCAPE           0x29
+#define TK_BACKSPACE        0x2A
+#define TK_TAB              0x2B
+#define TK_SPACE            0x2C
+#define TK_MINUS            0x2D /*  -  */
+#define TK_EQUALS           0x2E /*  =  */
+#define TK_LBRACKET         0x2F /*  [  */
+#define TK_RBRACKET         0x30 /*  ]  */
+#define TK_BACKSLASH        0x31 /*  \  */
+#define TK_SEMICOLON        0x33 /*  ;  */
+#define TK_APOSTROPHE       0x34 /*  '  */
+#define TK_GRAVE            0x35 /*  `  */
+#define TK_COMMA            0x36 /*  ,  */
+#define TK_PERIOD           0x37 /*  .  */
+#define TK_SLASH            0x38 /*  /  */
+#define TK_F1               0x3A
+#define TK_F2               0x3B
+#define TK_F3               0x3C
+#define TK_F4               0x3D
+#define TK_F5               0x3E
+#define TK_F6               0x3F
+#define TK_F7               0x40
+#define TK_F8               0x41
+#define TK_F9               0x42
+#define TK_F10              0x43
+#define TK_F11              0x44
+#define TK_F12              0x45
+#define TK_PAUSE            0x48 /* Pause/Break */
+#define TK_INSERT           0x49
+#define TK_HOME             0x4A
+#define TK_PAGEUP           0x4B
+#define TK_DELETE           0x4C
+#define TK_END              0x4D
+#define TK_PAGEDOWN         0x4E
+#define TK_RIGHT            0x4F /* Right arrow */
+#define TK_LEFT             0x50 /* Left arrow */
+#define TK_DOWN             0x51 /* Down arrow */
+#define TK_UP               0x52 /* Up arrow */
+#define TK_KP_DIVIDE        0x54 /* '/' on numpad */
+#define TK_KP_MULTIPLY      0x55 /* '*' on numpad */
+#define TK_KP_MINUS         0x56 /* '-' on numpad */
+#define TK_KP_PLUS          0x57 /* '+' on numpad */
+#define TK_KP_ENTER         0x58
+#define TK_KP_1             0x59
+#define TK_KP_2             0x5A
+#define TK_KP_3             0x5B
+#define TK_KP_4             0x5C
+#define TK_KP_5             0x5D
+#define TK_KP_6             0x5E
+#define TK_KP_7             0x5F
+#define TK_KP_8             0x60
+#define TK_KP_9             0x61
+#define TK_KP_0             0x62
+#define TK_KP_PERIOD        0x63 /* '.' on numpad */
+#define TK_SHIFT            0x70
+#define TK_CONTROL          0x71
+#define TK_ALT              0x72
+
+/*
+ * Mouse events/states
+ */
+#define TK_MOUSE_LEFT       0x80 /* Buttons */
+#define TK_MOUSE_RIGHT      0x81
+#define TK_MOUSE_MIDDLE     0x82
+#define TK_MOUSE_X1         0x83
+#define TK_MOUSE_X2         0x84
+#define TK_MOUSE_MOVE       0x85 /* Movement event */
+#define TK_MOUSE_SCROLL     0x86 /* Mouse scroll event */
+#define TK_MOUSE_X          0x87 /* Cusor position in cells */
+#define TK_MOUSE_Y          0x88
+#define TK_MOUSE_PIXEL_X    0x89 /* Cursor position in pixels */
+#define TK_MOUSE_PIXEL_Y    0x8A
+#define TK_MOUSE_WHEEL      0x8B /* Scroll direction and amount */
+#define TK_MOUSE_CLICKS     0x8C /* Number of consecutive clicks */
+
+/*
+ * If key was released instead of pressed, it's code will be OR'ed with TK_KEY_RELEASED:
+ * a) pressed 'A': 0x04
+ * b) released 'A': 0x04|VK_KEY_RELEASED = 0x104
+ */
+#define TK_KEY_RELEASED     0x100
+
+/*
+ * Virtual key-codes for internal terminal states/variables.
+ * These can be accessed via terminal_state function.
+ */
+#define TK_WIDTH            0xC0 /* Terminal window size in cells */
+#define TK_HEIGHT           0xC1
+#define TK_CELL_WIDTH       0xC2 /* Character cell size in pixels */
+#define TK_CELL_HEIGHT      0xC3
+#define TK_COLOR            0xC4 /* Current foregroung color */
+#define TK_BKCOLOR          0xC5 /* Current background color */
+#define TK_LAYER            0xC6 /* Current layer */
+#define TK_COMPOSITION      0xC7 /* Current composition state */
+#define TK_CHAR             0xC8 /* Translated ANSI code of last produced character */
+#define TK_WCHAR            0xC9 /* Unicode codepoint of last produced character */
+#define TK_EVENT            0xCA /* Last dequeued event */
+#define TK_FULLSCREEN       0xCB /* Fullscreen state */
+
+/*
+ * Other events
+ */
+#define TK_CLOSE            0xE0
+#define TK_RESIZED          0xE1
+
+/*
+ * Generic mode enum.
+ * Right now it is used for composition option only.
+ */
+#define TK_OFF                 0
+#define TK_ON                  1
+
+/*
+ * Input result codes for terminal_read function.
+ */
+#define TK_INPUT_NONE          0
+#define TK_INPUT_CANCELLED    -1
+
+/*
+ * Text printing alignment.
+ */
+#define TK_ALIGN_DEFAULT       0
+#define TK_ALIGN_LEFT          1
+#define TK_ALIGN_RIGHT         2
+#define TK_ALIGN_CENTER        3
+#define TK_ALIGN_TOP           4
+#define TK_ALIGN_BOTTOM        8
+#define TK_ALIGN_MIDDLE       12
+
+/*
+ * Terminal uses unsigned 32-bit value for color representation in ARGB order (0xAARRGGBB), e. g.
+ * a) solid red is 0xFFFF0000
+ * b) half-transparent green is 0x8000FF00
+ */
+typedef uint32_t color_t;
+
+typedef struct dimensions_t_
+{
+	int width;
+	int height;
+}
+dimensions_t;
+
+#if defined(BEARLIBTERMINAL_STATIC_BUILD)
+#  define TERMINAL_API
+#elif defined(_WIN32)
+#  if defined(BEARLIBTERMINAL_BUILDING_LIBRARY)
+#    define TERMINAL_API __declspec(dllexport)
+#  else
+#    define TERMINAL_API __declspec(dllimport)
+#  endif
+#else
+#  if defined(BEARLIBTERMINAL_BUILDING_LIBRARY) && __GNUC__ >= 4
+#    define TERMINAL_API __attribute__ ((visibility ("default")))
+#  else
+#    define TERMINAL_API
+#  endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+TERMINAL_API int terminal_open();
+TERMINAL_API void terminal_close();
+TERMINAL_API int terminal_set8(const int8_t* value);
+TERMINAL_API int terminal_set16(const int16_t* value);
+TERMINAL_API int terminal_set32(const int32_t* value);
+TERMINAL_API void terminal_refresh();
+TERMINAL_API void terminal_clear();
+TERMINAL_API void terminal_clear_area(int x, int y, int w, int h);
+TERMINAL_API void terminal_crop(int x, int y, int w, int h);
+TERMINAL_API void terminal_layer(int index);
+TERMINAL_API void terminal_color(color_t color);
+TERMINAL_API void terminal_bkcolor(color_t color);
+TERMINAL_API void terminal_composition(int mode);
+TERMINAL_API void terminal_font8(const int8_t* name);
+TERMINAL_API void terminal_font16(const int16_t* name);
+TERMINAL_API void terminal_font32(const int32_t* name);
+TERMINAL_API void terminal_put(int x, int y, int code);
+TERMINAL_API void terminal_put_ext(int x, int y, int dx, int dy, int code, color_t* corners);
+TERMINAL_API int terminal_pick(int x, int y, int index);
+TERMINAL_API color_t terminal_pick_color(int x, int y, int index);
+TERMINAL_API color_t terminal_pick_bkcolor(int x, int y);
+TERMINAL_API void terminal_print_ext8(int x, int y, int w, int h, int align, const int8_t* s, int* out_w, int* out_h);
+TERMINAL_API void terminal_print_ext16(int x, int y, int w, int h, int align, const int16_t* s, int* out_w, int* out_h);
+TERMINAL_API void terminal_print_ext32(int x, int y, int w, int h, int align, const int32_t* s, int* out_w, int* out_h);
+TERMINAL_API void terminal_measure_ext8(int w, int h, const int8_t* s, int* out_w, int* out_h);
+TERMINAL_API void terminal_measure_ext16(int w, int h, const int16_t* s, int* out_w, int* out_h);
+TERMINAL_API void terminal_measure_ext32(int w, int h, const int32_t* s, int* out_w, int* out_h);
+TERMINAL_API int terminal_has_input();
+TERMINAL_API int terminal_state(int code);
+TERMINAL_API int terminal_read();
+TERMINAL_API int terminal_read_str8(int x, int y, int8_t* buffer, int max);
+TERMINAL_API int terminal_read_str16(int x, int y, int16_t* buffer, int max);
+TERMINAL_API int terminal_read_str32(int x, int y, int32_t* buffer, int max);
+TERMINAL_API int terminal_peek();
+TERMINAL_API void terminal_delay(int period);
+TERMINAL_API const int8_t* terminal_get8(const int8_t* key, const int8_t* default_);
+TERMINAL_API const int16_t* terminal_get16(const int16_t* key, const int16_t* default_);
+TERMINAL_API const int32_t* terminal_get32(const int32_t* key, const int32_t* default_);
+TERMINAL_API color_t color_from_name8(const int8_t* name);
+TERMINAL_API color_t color_from_name16(const int16_t* name);
+TERMINAL_API color_t color_from_name32(const int32_t* name);
+TERMINAL_API int terminal_put_array(int x, int y, int w, int h, const uint8_t* data, int row_stride, int column_stride, const void* layout, int char_size);
+
+#ifdef __cplusplus
+} /* End of extern "C" */
+#endif
+
+/*
+ * Utility macro trick which allows macro-in-macro expansion
+ */
+#define TERMINAL_CAT(a, b) TERMINAL_PRIMITIVE_CAT(a, b)
+#define TERMINAL_PRIMITIVE_CAT(a, b) a ## b
+
+/*
+ * wchar_t has different sized depending on platform. Furthermore, it's size
+ * can be changed for GCC compiler.
+ */
+#if !defined(__SIZEOF_WCHAR_T__)
+#  if defined(_WIN32)
+#    define __SIZEOF_WCHAR_T__ 2
+#  else
+#    define __SIZEOF_WCHAR_T__ 4
+#  endif
+#endif
+
+#if __SIZEOF_WCHAR_T__ == 2
+#define TERMINAL_WCHAR_SUFFIX 16
+#define TERMINAL_WCHAR_TYPE int16_t
+#else // 4
+#define TERMINAL_WCHAR_SUFFIX 32
+#define TERMINAL_WCHAR_TYPE int32_t
+#endif
+
+#if defined(__cplusplus)
+#define TERMINAL_INLINE inline
+#define TERMINAL_DEFAULT(value) = value
+#else
+#define TERMINAL_INLINE static inline
+#define TERMINAL_DEFAULT(value)
+#endif
+
+/*
+ * These functions provide inline string formatting support
+ * for terminal_setf, terminal_printf, etc.
+ *
+ * Using static termporary buffer is okay because terminal API is not
+ * required to be multiple-thread safe by design.
+ */
+
+#define TERMINAL_VSPRINTF_MAXIMUM_BUFFER_SIZE 65536
+
+TERMINAL_INLINE const char* terminal_vsprintf(const char* s, va_list args)
+{
+	static int buffer_size = 512;
+	static char* buffer = NULL;
+	int rc = 0;
+
+	if (!s)
+		return NULL;
+	else if (!buffer)
+		buffer = (char*)malloc(buffer_size);
+
+	while (1)
+	{
+		buffer[buffer_size-1] = '\0';
+		rc = vsnprintf(buffer, buffer_size, s, args);
+		if (rc >= buffer_size || buffer[buffer_size-1] != '\0')
+		{
+			if (buffer_size >= TERMINAL_VSPRINTF_MAXIMUM_BUFFER_SIZE)
+				return NULL;
+
+			buffer_size *= 2;
+			buffer = (char*)realloc(buffer, buffer_size);
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	return rc >= 0? buffer: NULL;
+}
+
+TERMINAL_INLINE const wchar_t* terminal_vswprintf(const wchar_t* s, va_list args)
+{
+	static int buffer_size = 512;
+	static wchar_t* buffer = NULL;
+	int rc = 0;
+
+	if (!s)
+		return NULL;
+	else if (!buffer)
+		buffer = (wchar_t*)malloc(buffer_size * sizeof(wchar_t));
+
+	while (1)
+	{
+		buffer[buffer_size-1] = L'\0';
+#if defined(_WIN32)
+		rc = _vsnwprintf(buffer, buffer_size, s, args);
+#else
+		rc = vswprintf(buffer, buffer_size, s, args);
+#endif
+		if (rc >= buffer_size || buffer[buffer_size-1] != L'\0')
+		{
+			if (buffer_size >= TERMINAL_VSPRINTF_MAXIMUM_BUFFER_SIZE)
+				return NULL;
+
+			buffer_size *= 2;
+			buffer = (wchar_t*)realloc(buffer, buffer_size * sizeof(wchar_t));
+		}
+		else
+		{
+			break;
+		}
+	}
+
+	return rc >= 0? buffer: NULL;
+}
+
+#define TERMINAL_FORMATTED_WRAP(type, call) \
+	type ret; \
+	va_list args; \
+	va_start(args, s); \
+	ret = call; \
+	va_end(args); \
+	return ret;
+
+#define TERMINAL_FORMATTED_WRAP_V(call) \
+	va_list args; \
+	va_start(args, s); \
+	call; \
+	va_end(args);
+
+/*
+ * This set of inline functions define basic name substitution + type cast:
+ * terminal_[w]xxxx -> terminal_xxxx{8|16|32}
+ */
+
+TERMINAL_INLINE int terminal_set(const char* s)
+{
+	return terminal_set8((const int8_t*)s);
+}
+
+TERMINAL_INLINE int terminal_setf(const char* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(int, terminal_set(terminal_vsprintf(s, args)))
+}
+
+TERMINAL_INLINE int terminal_wset(const wchar_t* s)
+{
+	return TERMINAL_CAT(terminal_set, TERMINAL_WCHAR_SUFFIX)((const TERMINAL_WCHAR_TYPE*)s);
+}
+
+TERMINAL_INLINE int terminal_wsetf(const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(int, terminal_wset(terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE void terminal_font(const char* name)
+{
+	terminal_font8((const int8_t*)name);
+}
+
+TERMINAL_INLINE void terminal_wfont(const wchar_t* name)
+{
+	TERMINAL_CAT(terminal_font, TERMINAL_WCHAR_SUFFIX)((const TERMINAL_WCHAR_TYPE*)name);
+}
+
+TERMINAL_INLINE dimensions_t terminal_print(int x, int y, const char* s)
+{
+	dimensions_t ret;
+	terminal_print_ext8(x, y, 0, 0, TK_ALIGN_DEFAULT, (const int8_t*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_printf(int x, int y, const char* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_print(x, y, terminal_vsprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_wprint(int x, int y, const wchar_t* s)
+{
+	dimensions_t ret;
+	TERMINAL_CAT(terminal_print_ext, TERMINAL_WCHAR_SUFFIX)(x, y, 0, 0, TK_ALIGN_DEFAULT, (const TERMINAL_WCHAR_TYPE*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_wprintf(int x, int y, const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wprint(x, y, terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_print_ext(int x, int y, int w, int h, int align, const char* s)
+{
+	dimensions_t ret;
+	terminal_print_ext8(x, y, w, h, align, (const int8_t*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_printf_ext(int x, int y, int w, int h, int align, const char* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_print_ext(x, y, w, h, align, terminal_vsprintf(s, args)));
+}
+
+TERMINAL_INLINE dimensions_t terminal_wprint_ext(int x, int y, int w, int h, int align, const wchar_t* s)
+{
+	dimensions_t ret;
+	TERMINAL_CAT(terminal_print_ext, TERMINAL_WCHAR_SUFFIX)(x, y, w, h, align, (const TERMINAL_WCHAR_TYPE*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_wprintf_ext(int x, int y, int w, int h, int align, const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wprint_ext(x, y, w, h, align, terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_measure(const char* s)
+{
+	dimensions_t ret;
+	terminal_measure_ext8(0, 0, (const int8_t*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_measuref(const char* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_measure(terminal_vsprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_wmeasure(const wchar_t* s)
+{
+	dimensions_t ret;
+	TERMINAL_CAT(terminal_measure_ext, TERMINAL_WCHAR_SUFFIX)(0, 0, (const TERMINAL_WCHAR_TYPE*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_wmeasuref(const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wmeasure(terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_measure_ext(int w, int h, const char* s)
+{
+	dimensions_t ret;
+	terminal_measure_ext8(w, h, (const int8_t*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_measuref_ext(int w, int h, const char* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_measure_ext(w, h, terminal_vsprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_wmeasure_ext(int w, int h, const wchar_t* s)
+{
+	dimensions_t ret;
+	TERMINAL_CAT(terminal_measure_ext, TERMINAL_WCHAR_SUFFIX)(w, h, (const TERMINAL_WCHAR_TYPE*)s, &ret.width, &ret.height);
+	return ret;
+}
+
+TERMINAL_INLINE dimensions_t terminal_wmeasuref_ext(int w, int h, const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wmeasure_ext(w, h, terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE int terminal_read_str(int x, int y, char* buffer, int max)
+{
+	return terminal_read_str8(x, y, (int8_t*)buffer, max);
+}
+
+TERMINAL_INLINE int terminal_read_wstr(int x, int y, wchar_t* buffer, int max)
+{
+	return TERMINAL_CAT(terminal_read_str, TERMINAL_WCHAR_SUFFIX)(x, y, (TERMINAL_WCHAR_TYPE*)buffer, max);
+}
+
+TERMINAL_INLINE const char* terminal_get(const char* key, const char* default_ TERMINAL_DEFAULT((const char*)0))
+{
+	return (const char*)terminal_get8((const int8_t*)key, (const int8_t*)default_);
+}
+
+TERMINAL_INLINE const wchar_t* terminal_wget(const wchar_t* key, const wchar_t* default_ TERMINAL_DEFAULT((const wchar_t*)0))
+{
+	return (const wchar_t*)TERMINAL_CAT(terminal_get, TERMINAL_WCHAR_SUFFIX)((const TERMINAL_WCHAR_TYPE*)key, (const TERMINAL_WCHAR_TYPE*)default_);
+}
+
+TERMINAL_INLINE color_t color_from_name(const char* name)
+{
+	return color_from_name8((const int8_t*)name);
+}
+
+TERMINAL_INLINE color_t color_from_wname(const wchar_t* name)
+{
+	return TERMINAL_CAT(color_from_name, TERMINAL_WCHAR_SUFFIX)((const TERMINAL_WCHAR_TYPE*)name);
+}
+
+#ifdef __cplusplus
+/*
+ * C++ supports function overloading, should take advantage of it.
+ */
+
+TERMINAL_INLINE int terminal_set(const wchar_t* s)
+{
+	return terminal_wset(s);
+}
+
+TERMINAL_INLINE int terminal_setf(const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(int, terminal_wset(terminal_vswprintf(s, args)));
+}
+
+TERMINAL_INLINE void terminal_color(const char* name)
+{
+	terminal_color(color_from_name(name));
+}
+
+TERMINAL_INLINE void terminal_color(const wchar_t* name)
+{
+	terminal_color(color_from_wname(name));
+}
+
+TERMINAL_INLINE void terminal_bkcolor(const char* name)
+{
+	terminal_bkcolor(color_from_name(name));
+}
+
+TERMINAL_INLINE void terminal_bkcolor(const wchar_t* name)
+{
+	terminal_bkcolor(color_from_wname(name));
+}
+
+TERMINAL_INLINE void terminal_font(const wchar_t* name)
+{
+	terminal_wfont(name);
+}
+
+TERMINAL_INLINE void terminal_put_ext(int x, int y, int dx, int dy, int code)
+{
+	terminal_put_ext(x, y, dx, dy, code, 0);
+}
+
+TERMINAL_INLINE dimensions_t terminal_print(int x, int y, const wchar_t* s)
+{
+	return terminal_wprint(x, y, s);
+}
+
+TERMINAL_INLINE dimensions_t terminal_printf(int x, int y, const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wprint(x, y, terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_print_ext(int x, int y, int w, int h, int align, const wchar_t* s)
+{
+	return terminal_wprint_ext(x, y, w, h, align, s);
+}
+
+TERMINAL_INLINE dimensions_t terminal_printf_ext(int x, int y, int w, int h, int align, const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wprint_ext(x, y, w, h, align, terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_measure(const wchar_t* s)
+{
+	return terminal_wmeasure(s);
+}
+
+TERMINAL_INLINE dimensions_t terminal_measuref(const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wmeasure(terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE dimensions_t terminal_measure_ext(int w, int h, const wchar_t* s)
+{
+	return terminal_wmeasure_ext(w, h, s);
+}
+
+TERMINAL_INLINE dimensions_t terminal_measuref_ext(int w, int h, const wchar_t* s, ...)
+{
+	TERMINAL_FORMATTED_WRAP(dimensions_t, terminal_wmeasure_ext(w, h, terminal_vswprintf(s, args)))
+}
+
+TERMINAL_INLINE int terminal_read_str(int x, int y, wchar_t* buffer, int max)
+{
+	return terminal_read_wstr(x, y, buffer, max);
+}
+
+TERMINAL_INLINE color_t color_from_name(const wchar_t* name)
+{
+	return color_from_wname(name);
+}
+
+TERMINAL_INLINE int terminal_pick(int x, int y)
+{
+	return terminal_pick(x, y, 0);
+}
+
+TERMINAL_INLINE color_t terminal_pick_color(int x, int y)
+{
+	return terminal_pick_color(x, y, 0);
+}
+
+TERMINAL_INLINE const wchar_t* terminal_get(const wchar_t* key, const wchar_t* default_ = (const wchar_t*)0)
+{
+	return terminal_wget(key, default_);
+}
+
+template<typename T, typename C> T terminal_get(const C* key, const T& default_ = T())
+{
+	const C* result_str = terminal_get(key, (const C*)0);
+	if (result_str[0] == C(0))
+		return default_;
+	T result;
+	return (bool)(std::basic_istringstream<C>(result_str) >> result)? result: default_;
+}
+
+#endif /* __cplusplus */
+
+/*
+ * Color routines
+ */
+TERMINAL_INLINE color_t color_from_argb(uint8_t a, uint8_t r, uint8_t g, uint8_t b)
+{
+	return ((color_t)a << 24) | (r << 16) | (g << 8) | b;
+}
+
+/*
+ * Other functional sugar
+ */
+TERMINAL_INLINE int terminal_check(int code)
+{
+	return terminal_state(code) > 0;
+}
+
+/*
+ * WinMain entry point handling macro. This allows easier entry point definition.
+ * The macro will expand to proper WinMain stub regardless of header include order.
+ */
+#if defined(_WIN32)
+
+/*
+ * WinMain probe macro. It will expand to either X or X_WINDOWS_ depending on
+ * Windows.h header inclusion.
+ */
+#define TERMINAL_TAKE_CARE_OF_WINMAIN TERMINAL_WINMAIN_PROBE_IMPL(_WINDOWS_)
+#define TERMINAL_WINMAIN_PROBE_IMPL(DEF) TERMINAL_PRIMITIVE_CAT(TERMINAL_WINMAIN_IMPL, DEF)
+
+/*
+ * Trivial no-arguments WinMain implementation. It just calls main.
+ */
+#define TERMINAL_WINMAIN_IMPL_BASE(INSTANCE_T, STRING_T)\
+	extern "C" int main();\
+	extern "C" int __stdcall WinMain(INSTANCE_T hInstance, INSTANCE_T hPrevInstance, STRING_T lpCmdLine, int nCmdShow)\
+	{\
+		return main();\
+	}
+
+/*
+ * Macro expands to empty string. Windows.h is included thus code MUST use
+ * predefined types or else MSVC will complain.
+ */
+#define TERMINAL_WINMAIN_IMPL TERMINAL_WINMAIN_IMPL_BASE(HINSTANCE, LPSTR)
+
+/*
+ * Macro expands to macro name. Windows.h wasn't included, so WinMain will be
+ * defined with fundamental types (enough for linker to find it).
+ */
+#define TERMINAL_WINMAIN_IMPL_WINDOWS_ TERMINAL_WINMAIN_IMPL_BASE(void*, char*)
+
+#else
+
+/*
+ * Only Windows has WinMain but macro still must be defined for cross-platform
+ * applications.
+ */
+#define TERMINAL_TAKE_CARE_OF_WINMAIN
+
+#endif
+
+#endif // BEARLIBTERMINAL_H
+ cbits/BearLibTerminalExtras.h view
@@ -0,0 +1,41 @@+#ifndef BEARLIBTERMINALEXTRAS_H+#define BEARLIBTERMINALEXTRAS_H++#include "BearLibTerminal.h"+#include <string.h>++void terminal_color_from_name(const char* name)+{+	terminal_color(color_from_name(name));+}++void terminal_bkcolor_from_name(const char* name)+{+	terminal_bkcolor(color_from_name(name));+}++void terminal_print_ptr(int x, int y, const char* s, dimensions_t* dim)+{+  dimensions_t d = terminal_print(x, y, s);+	memcpy(dim, &d, sizeof(*dim));+}++void terminal_print_ext_ptr(int x, int y, int w, int h, int align, const char* s, dimensions_t* dim)+{+	dimensions_t d = terminal_print_ext(x, y, w, h, align, s);+	memcpy(dim, &d, sizeof(*dim));+}++void terminal_measure_ptr(const char* s, dimensions_t* dim)+{+	dimensions_t d = terminal_measure(s);+	memcpy(dim, &d, sizeof(*dim));+}++void terminal_measure_ext_ptr(int w, int h, const char* s, dimensions_t* dim)+{+	dimensions_t d = terminal_measure_ext(w, h, s);+	memcpy(dim, &d, sizeof(*dim));+}++#endif
+ omni/Main.hs view
@@ -0,0 +1,82 @@+module Main+  ( main+  ) where++import BearLibTerminal+import Control.Monad+import Control.Exception+import Data.Text ( Text )+import qualified Data.Text as T+import Omni.BasicOutput+import qualified Data.Map as M+import Omni.DefaultFont (defaultFont)+import Omni.Tilesets+import Omni.ManualCellsize++main :: IO ()+main = do+  bracket_+    (terminalOpen_ >> resetTerminal)+    terminalClose+    runLoop++runLoop :: IO ()+runLoop = do+  terminalClear+  printEntries+  void $ terminalPrint 2 23 "[color=orange]ESC.[/color] Exit"+  void $ terminalPrintExt 77 22 0 0 (Just AlignRight) "library version 0.1.0.0"+  void $ terminalPrintExt 77 23 0 0 (Just AlignRight) "BearLibTerminal (Hello from Haskell!)"+  terminalRefresh+  c <- terminalRead+  case c of+    TkEscape ->return ()+    TkClose -> return ()+    x -> maybe runLoop (>> runLoop) (M.lookup x entryMap )++entryPresses :: [Keycode]+entryPresses = [ Tk1 .. Tk9 ] <> [TkA .. TkK]++entryMap :: M.Map Keycode (IO ())+entryMap = M.fromList $ zip entryPresses (map snd entries)++entries :: [(Text, IO ())]+entries =+  [ ("Basic output", basicOutput)+  , ("Default font", defaultFont)+  , ("Tilesets", tilesets)+  , ("Sprites", return ()) -- TODO+  , ("Manual cellsize", manualCellsize)+  , ("Auto-generated tileset", return ())  -- TODO+  , ("Multiple fonts", return ())  -- TODO+  , ("Text alignment", return ())  -- TODO+  , ("Formatted log", return ()) -- TODO+  , ("Layers", return ()) -- TODO+  , ("Extended 1: basics", return ()) -- TODO+  , ("Extended 2: smooth scroll", return ()) -- TODO+  , ("Dynamic sprites", return ()) -- TODO+  , ("Speed", return ()) -- TODO+  , ("Input 1: keyboard", return ()) -- TODO+  , ("Input 2: mouse", return ()) -- TODO+  , ("Input 3: text input", return ()) -- TODO+  , ("Input 4: filtering", return ()) -- TODO+  , ("Window resizing", return ()) -- TODO+  , ("Examining cell contents", return ()) -- TODO+  ]++printEntry :: (Int, (Text, IO ())) -> IO ()+printEntry (i, (n, _)) = do+  let shortcut = toEnum $ if i < 9 then fromEnum '1' + i else fromEnum 'a' + (i-9)+  let col = if i `elem` ([0..2] <> [4]) then "white" else "gray"+  void $ terminalPrint 2 (1+i) (mconcat ["[color=orange]", T.singleton shortcut, ".[/color][color="<>col<>"]", n])++printEntries :: IO ()+printEntries = mapM_ printEntry (zip [0..] entries)+++resetTerminal :: IO ()+resetTerminal = do+  -- TODO: I moved all the actual helper stuff to roguefunctor..+  -- todo: font:default, input filter to keyboard+  --void $ terminalSetText "" defaultWindowOptions { title = Just "Omni: menu" }+  terminalColorName "white"
+ omni/Omni/BasicOutput.hs view
@@ -0,0 +1,49 @@+module Omni.BasicOutput where+import BearLibTerminal.Terminal.Set+import BearLibTerminal+import Control.Monad (forM_)+import Data.Text as T hiding (zip)++orangeText :: Text -> Text+orangeText = textColor "orange"+basicOutput :: IO ()+basicOutput = do+  terminalSetTitle "Omni: basic output"+  terminalClear+  terminalColorName "white"++  n <- width <$> terminalPrint 2 1 (textColor "orange" "1. " <> "Wide color range: ")+  let longWord :: String+      longWord = "antidisestablishmentarianism."++  forM_ (zip @Int [0..] longWord) $ \(i, c) -> do+    let factor :: Double+        factor = fromIntegral i / fromIntegral n+        red = round @_ @Int $ (1.0 - factor) * 255+        green = round $ factor * 255+    terminalColorUInt (colorFromRGB red green 0)+    terminalPut (2+n+i) 1 c++  terminalColorName "white"+  terminalPrint_ 2 3 (mconcat [orangeText "2. ", "Backgrounds: ", textColor "black" (textBkColor "gray" "grey" <> " " <> textBkColor "red" "red")])++  terminalPrint_ 2 5 (orangeText "3. " <> "Unicode support: Кириллица Ελληνικά α=β²±2°")++  terminalPrint_ 2 7 (orangeText "4. " <> "Tile composition: a + [color=red]/[/color] = a[+][color=red]/[/color], a vs. a[+][color=red]¨[/color]")++  terminalPrint_ 2 9 "[color=orange]5. [/color]Box drawing symbols:"+  terminalPrint_ 5 11 $ T.unlines+    [ "   ┌────────┐  "+    , "   │!......s└─┐"+    , "┌──┘........s.│"+    , "│............>│"+    , "│...........┌─┘"+    , "│<.@..┌─────┘  "+    , "└─────┘        "+    ]+  terminalRefresh+  c <- terminalRead+  case c of+    TkEscape -> return ()+    TkClose -> return ()+    _ -> basicOutput
+ omni/Omni/DefaultFont.hs view
@@ -0,0 +1,125 @@+module Omni.DefaultFont where+import BearLibTerminal+import BearLibTerminal.Terminal.Print+import Data.Text hiding (zipWith, length, elem, map)+import Control.Monad+import qualified Data.Vector as V+import Formatting+import Control.Monad.State+import BearLibTerminal.Keycodes++data Range = Range+  { name :: Text+  , rangeStart :: Int+  , rangeEnd :: Int+  , codes :: [Int]+  , rangeId :: Int+  }++ranges :: V.Vector Range+ranges = V.fromList $ zipWith (\i x -> x i) [0..]+  [ Range "C0 Controls and Basic Latin" 0x0020 0x007F [0x0020 .. 0x007F]+  , Range "C1 Controls and Latin-1 Supplement" 0x0080 0x00FF [0x00A0 .. 0x00FF]+  , Range "Latin Extended-A" 0x0100 0x017F [0x0100 .. 0x017F]+  , Range "Latin Extended-B" 0x0180 0x024F (0x0192 : [0x01FA .. 0x01FF])+  , Range "Spacing Modifier Letters" 0x02B0 0x02FF ([0x02C6, 0x02C7, 0x02C9] <> [0x02D8 .. 0x02DD])+  , Range "Greek and Coptic" 0x0370 0x03FF $ mconcat [ 0x037E : [0x0384 .. 0x038A], 0x038C : [0x038E .. 0x03A1], [0x03A3 .. 0x03CE]]++  , Range "Cyrillic" 0x0400 0x04FF $ [0x0400 .. 0x045F] <> [0x0490 .. 0x0491]+  , Range "Latin Extended Additional" 0x1E00 0x1EFF $ [0x1E80 .. 0x1E85] <> [0x1EF2 .. 0x1EF3]+  , Range "General Punctuation" 0x2000 0x206F $ mconcat $+        [ [0x2013 .. 0x2015]+        , [0x2017 .. 0x201E]+        , [0x2020 .. 0x2022]+        , [0x2026, 0x2030]+        , [0x2032 .. 0x2033]+        , [0x2039 .. 0x203A]+        , [0x203C, 0x203E, 0x2044]+        ]+  , Range "Superscripts and Subscript" 0x2070 0x209F [0x207F]++  , Range "Currency Symbols" 0x20A0 0x20CF $ [0x20A3 .. 0x20A4] <> [0x20A7, 0x20AC]++  , Range "Letterlike Symbols" 0x2100 0x214F [0x2105, 0x2113, 0x2116, 0x2122, 0x2126, 0x212E]++  , Range "Number Forms" 0x2150 0x218F [0x215B, 0x215E]++  , Range "Arrows" 0x2190 0x21FF $ [0x2190 .. 0x2195] <> [0x21A8]++  , Range "Mathematical Operators" 0x2200 0x22FF $ mconcat+    [ [0x2202, 0x2206, 0x220F]+    , [0x2211 .. 0x2212]+    , [0x2215]+    , [0x2219 .. 0x221A]+    , [0x221E .. 0x221F]+    , [0x2229, 0x222B, 0x2248]+    , [0x2260 .. 0x2261]+    , [0x2264 .. 0x2265]+    ]++  , Range "Miscellaneous Technical" 0x2300 0x23FF $ [0x2302, 0x2310] <> [0x2320 .. 0x2321]++  , Range "Box Drawing" 0x2500 0x257F [0x2500 .. 0x257F]++  , Range "Block Elements" 0x2580 0x259F [0x2580 .. 0x259F]++  , Range "Geometric Shapes" 0x25A0 0x25FF $ mconcat+    [ [0x25A0 .. 0x25A1]+    , [0x25AA .. 0x25AC]+    , [0x25B2, 0x25BA, 0x25BC, 0x25C4]+    , [0x25CA .. 0x25CB]+    , [0x25CF]+    , [0x25D8 .. 0x25D9]+    , [0x25E6]+    ]++  , Range "Miscellaneous Symbols" 0x2600 0x26FF $ mconcat+    [ [0x263A .. 0x263C]+    , [0x2640, 0x2642, 0x2660, 0x2663]+    , [0x2665 .. 0x2666]+    , [0x266A .. 0x266B]+    ]++  , Range "Private Use Area" 0xF000 0xF00F [0xF001 .. 0xF002]++  , Range "Alphabet presentation form" 0xFB00 0xFB0F [0xFB01 .. 0xFB02]+  ]++hOffset :: Int+hOffset = 40++defaultFont :: IO ()+defaultFont = do+  terminalSet_ "window: size=80x25, cellsize=auto, title='Omni: WGL4'; font=default"+  loop 0++loop :: Int -> IO ()+loop currentSelection = do+  terminalClear+  terminalPrint_ 2 1 "[color=white]Select unicode character range:"+  flip V.mapM_ ranges $ \range -> do+    terminalColorName (if rangeId range == currentSelection then "orange" else "light gray")+    terminalPrint_ 1 (2 + rangeId range) (sformat (stext % stext) (if rangeId range == currentSelection then "[\x203A]" else " ") (name range))+  let currRange = ranges V.! currentSelection+  forM_ [0..15] $ \j -> terminalPrint (hOffset+ 6 + j*2) 1 (sformat ("[color=orange]" % hex) j)++  flip evalStateT 0 $ forM_ [rangeStart currRange .. rangeEnd currRange] $ \code -> do+    y <- get+    when (code `mod` 16 == 0) $ terminalPrint_ hOffset (2+y) (sformat ("[color=orange]" % hexPrefix 4 % ":") code)+    let included = code `elem` codes currRange+    terminalColorName (if included then "white" else "dark gray")+    terminalPutInt (hOffset + 6 + (code `mod` 16) *2) (2+y) code+    when ((code+1) `mod` 16 == 0) $ modify (+ 1)++  terminalColorName "white"+  terminalPrint_ hOffset 20 "[color=orange]TIP:[/color] Use ↑/↓ keys to select range"+  terminalPrint_ hOffset 22 "[color=orange]NOTE:[/color] Character code points printed in\ngray are not included in the WGL4 set."++  terminalRefresh+  c <- terminalRead+  case c of+    x+      | x `elem` [TkEscape, TkClose] -> return ()+    TkUp -> when (currentSelection > 0) $ loop (currentSelection - 1)+    TkDown -> when (currentSelection < length ranges - 1) $ loop (currentSelection + 1)+    _ -> loop currentSelection
+ omni/Omni/ManualCellsize.hs view
@@ -0,0 +1,70 @@+module Omni.ManualCellsize where++import BearLibTerminal+import Control.Monad (when)+import Control.Monad.State+import Data.Functor (void)+import Formatting+import qualified Data.Vector as V++data GuiState = GuiState+  { hinting :: Int+  , size :: Int+  , cellWidth :: Int+  , cellHeight :: Int+  }++initialGui :: GuiState+initialGui = GuiState 0 12 8 16++manualCellsize :: IO ()+manualCellsize = do+  terminalSet_ "window.title='Omni: manual cellsize'"++  let font = "Media/VeraMono.ttf"+      fontHintings = V.fromList ["normal", "autohint", "none"]+      setupCellsize = do+        s <- get+        terminalSet_ (sformat ("window: cellsize=" % int % "x" % int) (cellWidth s) (cellHeight s))+      setupFont = do+        s <- get+        terminalSet_ $ sformat ("font: " % stext % ", size=" % int % ", hinting=" % stext) font (size s) (fontHintings V.! hinting s)+      runLoop = do+        s <- get+        terminalClear+        terminalColorName "white"+        terminalPrint_ 2 1 "Hello, world!"+        void $ terminalPrintString 2 3 $ "[color=orange]Font size:[/color] " <> show (size s)+        terminalPrint_ 2 4 $ "[color=orange]Font hinting:[/color] " <> (fontHintings V.! hinting s)+        terminalPrint_ 2 5 $ sformat ("[color=orange]Cell size:[/color] " % int % "x" % int) (cellWidth s) (cellHeight s)+        terminalPrint_ 2 7 "[color=orange]TIP:[/color] Use arrow keys to change cell size"+        terminalPrint_ 2 8 "[color=orange]TIP:[/color] Use Shift+Up/Down arrow keys to change font size"+        terminalPrint_ 2 9 "[color=orange]TIP:[/color] Use TAB to switch font hinting mode"++        terminalRefresh+        k <- terminalRead+        case k of+          _+            | k == TkClose || k == TkEscape -> return ()+          TkLeft+            | cellWidth s > 4 -> ifShift (return ()) (modify (\s' -> s' { cellWidth = cellWidth s - 1}) >> setupCellsize)+          TkRight+            | cellWidth s < 24 -> ifShift (return ()) (modify (\s' -> s' { cellWidth = cellWidth s + 1}) >> setupCellsize)+          TkDown -> ifShift+                      (when (size s > 4) $ modify (\s' -> s' { size = size s - 1}) >> setupFont )+                      (when (cellHeight s < 24) $ modify (\s' -> s' { cellHeight = cellHeight s + 1}) >> setupCellsize)+          TkUp -> ifShift+                      (when (size s < 64) $ modify (\s' -> s' { size = size s + 1}) >> setupFont  )+                      (when (cellHeight s > 4) $ modify (\s' -> s' { cellHeight = cellHeight s - 1}) >> setupCellsize)+          TkTab -> modify (\s' -> s' { hinting = (hinting s + 1) `mod` V.length fontHintings}) >> setupFont >> runLoop+          _ -> runLoop+      ifShift yes no = do+        shiftPressed <- terminalKeyState TkShift+        if shiftPressed then yes else no+        runLoop++  flip evalStateT initialGui $ do+    setupCellsize+    setupFont+    runLoop+  terminalSet_ "font: default; window.cellsize=auto"
+ omni/Omni/Tilesets.hs view
@@ -0,0 +1,59 @@+module Omni.Tilesets where++import BearLibTerminal+import Control.Monad++tilesets :: IO ()+tilesets = do+  terminalComposition CompositionOn+  terminalSet_ "window.title='Omni: tilesets"+  terminalSet_ "U+E100: Media/Runic.png, size=8x16"+  terminalSet_ "U+E200: Media/Tiles.png, size=32x32, align=top-left"+  terminalSet_ "U+E300: Media/fontawesome-webfont.ttf, size=24x24, spacing=3x2, codepage=Media/fontawesome-codepage.txt"+  terminalSet_ "zodiac font: Media/Zodiac-S.ttf, size=24x36, spacing=3x3, codepage=437"++  terminalClear+  terminalColorName "white"++  terminalPrint_ 2 1 "[color=orange]1.[/color] Of course, there is default font tileset."++  terminalPrint_ 2 3 "[color=orange]2.[/color] You can load some arbitrary tiles and use them as glyphs:"+  terminalPrint_ (2+3) 4 $ "Fire rune ([color=red][U+E102][/color]), " <> "water rune ([color=lighter blue][U+E103][/color]), " <> "earth rune ([color=darker green][U+E104][/color])"++  terminalPrint_ 2 6 "[color=orange]3.[/color] Tiles are not required to be of the same size as font symbols:"+  terminalPutInt (2+3+0) 7 (0xE200+7)+  terminalPutInt (2+3+5) 7 (0xE200+8)+  terminalPutInt (2+3+10) 7 (0xE200+9)++  terminalPrint_ 2 10 "[color=orange]4.[/color] Like font characters, tiles may be freely colored and combined:"+  terminalPutInt (2+3+0) 11 (0xE200+8)+  terminalColorName "lighter orange"+  terminalPutInt (2+3+5) 11 (0xE200+8)+  terminalColorName "orange"+  terminalPutInt (2+3+10) 11 (0xE200+8)+  terminalColorName "dark orange"+  terminalPutInt (2+3+15) 11 (0xE200+8)++  terminalColorName "white"+  let order = zip [0..] [11, 10, 14, 12, 13]+  forM_ order $ \(i, o) -> do+    terminalPutInt (2+3+25+i*4) 11 (0xE200+o)+    terminalPutInt (2+3+25+(length order +1)*4) 11 (0xE200+o)+  terminalPutInt (2+3+25+length order*4) 11 (0xE200+15)++  terminalPrint_ 2 14 "[color=orange]5.[/color] And tiles can even come from TrueType fonts like this:"+  forM_ [0..5] $ \i -> terminalPutInt (2+3+i*5) 15 (0xE300+i)++  terminalPrint_ (2+3) 18 "...or like this:\n[font=zodiac]D F G S C"++  terminalRefresh++  c <- terminalRead+  case c of+    TkClose -> finish+    TkEscape -> finish+    _ -> tilesets+  where+    finish = do+      terminalSet_ "U+E100: none; U+E200: none; U+E300: none; zodiac font: none"+      terminalComposition CompositionOff
+ src/BearLibTerminal.hs view
@@ -0,0 +1,407 @@+{-|+Module      : BearLibTerminal.Keycodes+Description : String functions taking `CString`s.+License     : MIT+Stability   : experimental+Portability : POSIX++  A low-ish level binding to BearLibTerminal. For the most part this is 1-to-1 to the original C/C++ API+    and the raw bindings in `BearLibTerminal.Raw` are almost identical (the only differences being that intcode+    return types are wrapped into Booleans where relevant).+  For functions that expect strings, 3 variants exist:++    - `Text`. This one is strongly preferred because of the performance benefits of `Text` over `String`. These versions+    are available without a suffix - e.g. `terminalSet`, `terminalPrint_`.+    - `String`. Available with a `String` suffix - e.g. `terminalSetString`, `terminalPrintString_`.+    - `CString`. These aren't exported from this module but are available in `BearLibTerminal.Terminal.CString` if you+      do need them. They also do not have `m ()` variants.++  As this library is a low-level wrapper, the original BearLibTerminal documentation is an excellent reference!+  http://foo.wyrd.name/en:bearlibterminal:reference+-}++module BearLibTerminal+  (+  -- * Initialisation and configuration+  -- ** Open+  -- | For initialising a BearLibTerminal instance and opening a window.+    terminalOpen, terminalOpen_+  -- ** Close+  -- | For deinitialising a BearLibTerminal instance and closing the window.+  , terminalClose+  -- ** Set++  -- | For setting configuration options via configuration strings.+  , terminalSet, terminalSetString+  , terminalSet_, terminalSetString_+  -- * Output state++  -- ** Color+  , colorFromARGB+  , colorFromRGB+  -- *** Foreground+  , terminalColorUInt+  , terminalColorName+  , terminalColorNameString+  -- *** Background+  , terminalBkColorUInt+  , terminalBkColorName+  , terminalBkColorNameString++  -- ** Composition+  , TerminalCompositionMode(..)+  , terminalComposition+  -- ** Layer+  , terminalLayer++  -- * Output+  -- ** Print++  -- | These wrap @terminal_print@ and @terminal_print_ext@ in various string flavours.+  -- These *do* support the inline formatting options that BearLibTerminal itself supports, such as using @[color=red]@,+  -- pixel offsets, different fonts, and more. For more information check the BearLibTerminal documentation for+  -- [@terminal_print@](http://foo.wyrd.name/en:bearlibterminal:reference#print).+  , PrintAlignment(..)+  , Dimensions(..)+  , textColor+  , textBkColor+  , terminalPrint+  , terminalPrint_+  , terminalPrintExt+  , terminalPrintExt_++  , terminalPrintString+  , terminalPrintString_+  , terminalPrintExtString+  , terminalPrintExtString_++  -- ** Put+  , terminalPut+  , terminalPutInt+  , terminalPutExt++  -- ** Measure+  , terminalMeasureText+  , terminalMeasureString+  , terminalMeasureExtText+  , terminalMeasureExtString++  -- ** Refresh+  , terminalRefresh+  -- ** Clear+  , terminalClear+  , terminalClearArea+  , terminalCrop+  -- * Input+  -- ** Events+  , module BearLibTerminal.Keycodes+  , Keycode(..)++  , terminalPeek+  , terminalPeekCode+  , terminalHasInput+  , terminalRead+  , terminalReadCode+  -- ** Reading strings+  , terminalReadString+  -- ** State+  , terminalState+  , terminalKeyState+  -- ** Picking+  , terminalPick+  , terminalPickColor+  -- * Utility+  , terminalDelay+  ) where++++import BearLibTerminal.Keycodes+import BearLibTerminal.Raw+import BearLibTerminal.Terminal.CString+import BearLibTerminal.Terminal.Color+import BearLibTerminal.Terminal.Print+import BearLibTerminal.Terminal.Set+import BearLibTerminal.Terminal.String+import Control.Exception+import Control.Monad.IO.Class+import Data.Char (ord)+import Data.Coerce (coerce)+import Data.Text (Text)+import Foreign+import Foreign.C (CUInt)+import GHC.Generics+import qualified Data.Text.Foreign as T+maxStringReadSizeInBytes :: Int+maxStringReadSizeInBytes = 8192++-- | Create a new window with the default parameters. Does not display the window until the first call to `terminalRefresh`.+--+-- Wrapper around [@terminal_open@](http://foo.wyrd.name/en:bearlibterminal:reference#open).+terminalOpen :: MonadIO m+  => m Bool -- ^ whether the window creation was successful.+terminalOpen = asBool <$> liftIO c_terminal_open++-- | Create a new window with the default parameters. Does not display the window until the first call to `terminalRefresh`.+-- Ignore the success return value.+-- Wrapper around [@terminal_open@](http://foo.wyrd.name/en:bearlibterminal:reference#open).+terminalOpen_ :: MonadIO m+  => m ()+terminalOpen_ = liftIO $ void c_terminal_open++-- | Close the window and cleanup the BearLibTerminal instance.+--+-- Wrapper around [@terminal_close@](http://foo.wyrd.name/en:bearlibterminal:reference#close).+terminalClose ::+  MonadIO m+  => m ()+terminalClose = liftIO c_terminal_close++-- | Draw a single character (given by its code point) onto the screen on the currently selected layer+-- with the currently selected colors. This takes an `Int` rather than `Char` to avoid possible headaches+-- with mismatching character codes over string conversion. If you know you are wanting to render single+-- *characters* (rather than *code points*), consider using `terminalPrintText` (or similar) instead.+--+-- Wrapper around [@terminal_put@](http://foo.wyrd.name/en:bearlibterminal:reference#put)+terminalPutInt ::+  MonadIO m+  => Int -- ^ x-coordinate to print the character to.+  -> Int -- ^ y-coordinate to print the character to.+  -> Int -- ^ Unicode code point of the character to print.+  -> m ()+terminalPutInt x y c = liftIO $ c_terminal_put (fromIntegral x) (fromIntegral y) (fromIntegral c)++-- | Draw a single character (given by its code point) onto the screen on the currently selected layer+-- with the currently selected colors. This does take `Char` over `Int`, but possible problems with+-- encodings, unicode, all that jazz - you're on your own. If you know your way around string encodings+-- and can advise, please do!+--+-- Wrapper around [@terminal_put@](http://foo.wyrd.name/en:bearlibterminal:reference#put)+terminalPut ::+  MonadIO m+  => Int -- ^ x-coordinate to print the character to.+  -> Int -- ^ y-coordinate to print the character to.+  -> Char -- ^ Unicode code point of the character to print.+  -> m ()+terminalPut x y c = liftIO $ c_terminal_put (fromIntegral x) (fromIntegral y) (fromIntegral $ ord c)++-- | Data type to represent whether cell composition should be turned on or off.+data TerminalCompositionMode =+  CompositionOn -- ^ Turn cell composition on; i.e. repeated prints to the same location on the same layer will stack the tiles.+  | CompositionOff-- ^ Turn cell composition off; i.e. repeated prints to the same location on the same layer will overwrite the existing tiles.+  deriving stock (Eq, Ord, Show, Generic, Read, Enum, Bounded)++-- | Enable or disable terminal composition.+--+-- Wrapper around [@terminal_composition@](http://foo.wyrd.name/en:bearlibterminal:reference#composition)+terminalComposition ::+  MonadIO m+  => TerminalCompositionMode -- ^ composition mode to set.+  -> m ()+terminalComposition = liftIO . c_terminal_composition .+  (\case+    CompositionOff -> 0+    CompositionOn -> 1+  )++-- | Set the currently selected layer to be used by following output functions (e.g. `terminalPrintText`).+--+-- Wrapper around [@terminal_layer@](http://foo.wyrd.name/en:bearlibterminal:reference#layer).+terminalLayer ::+  MonadIO m+  => Int -- ^ layer to select (0-255 inclusive).+  -> m ()+terminalLayer = liftIO . c_terminal_layer . fromIntegral++-- | Clear the entire screen (all layers) with the currently selected background color (`terminalBkColorUInt` and family).+--+-- Wrapper around [@terminal_clear@](http://foo.wyrd.name/en:bearlibterminal:reference#clear).+terminalClear :: MonadIO m => m ()+terminalClear = liftIO c_terminal_clear++-- | Clear a rectangular area on the currently selected layer. This only sets the background color+-- on layer 0.+--+-- Wrapper around [@terminal_clear_area@](http://foo.wyrd.name/en:bearlibterminal:reference#clear_area).+terminalClearArea ::+  MonadIO m+  => Int -- ^ x-coordinate of the top left of the rectangular area.+  -> Int -- ^ y-coordinate of the top left of the rectangular area.+  -> Int -- ^ width of the rectangular area.+  -> Int  -- ^ height of the rectangular area.+  -> m ()+terminalClearArea x y w h = liftIO (c_terminal_clear_area (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h))++-- | Set a cropping area for the currently selected layer. Anything printed outside of this region+-- will be ignored. Set the width or height to zero or use `terminalClear` to reset this.+--+-- Wrapper around [@terminal_crop@](http://foo.wyrd.name/en:bearlibterminal:reference#crop).+terminalCrop ::+  MonadIO m+  => Int -- ^ x-coordinate of the top left of the rectangular area.+  -> Int -- ^ y-coordinate of the top left of the rectangular area.+  -> Int -- ^ width of the rectangular area.+  -> Int  -- ^ height of the rectangular area.+  -> m ()+terminalCrop x y w h = liftIO (c_terminal_crop (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h))++-- | Commit the scene to be rendered and redraw the window. This needs to be called once after `terminalOpen`+-- before the window will be displayed.+--+-- Wrapper around [@terminal_refresh@](http://foo.wyrd.name/en:bearlibterminal:reference#crop).+terminalRefresh :: MonadIO m => m ()+terminalRefresh = liftIO c_terminal_refresh++-- | Return the code of the tile in the specified cell on the current layer at the current index+-- in the tile stack.+--+-- Wrapper around [@terminal_pick@](http://foo.wyrd.name/en:bearlibterminal:reference#pick).+terminalPick ::+  MonadIO m+  => Int -- ^ x-coordinate of the tile to be queried.+  -> Int -- ^ y-coordinate of the tile to be queried.+  -> Int  -- ^ index of the symbol in the cell to be returned.+  -> m (Maybe Int) -- ^ `Just codepoint` if the symbol exists and `Nothing` otherwise.+terminalPick x y i = liftIO $ (\x' -> if x' == 0 then Nothing else Just $ fromIntegral x') <$> c_terminal_pick (fromIntegral x) (fromIntegral y) (fromIntegral i)++-- | Return the foreground color of the tile in the specified cell on the current layer at the current index+-- in the tile stack.+--+-- Wrapper around [@terminal_pick_color@](http://foo.wyrd.name/en:bearlibterminal:reference#pick_color).+terminalPickColor ::+  MonadIO m+  => Int -- ^ x-coordinate of the tile to be queried.+  -> Int -- ^ y-coordinate of the tile to be queried.+  -> Int  -- ^ index of the symbol in the cell to be returned.+  -> m Integer -- ^ Color of the foreground if the symbol exists.+terminalPickColor x y i = liftIO $ fromIntegral <$> c_terminal_pick_color (fromIntegral x) (fromIntegral y) (fromIntegral i)++-- | Return the background color of the tile in the specified cell.+--+-- Wrapper around [@terminal_pick_bkcolor@](http://foo.wyrd.name/en:bearlibterminal:reference#pick_bkcolor).+terminalPickBkColor ::+  MonadIO m+  => Int -- ^ x-coordinate of the tile to be queried.+  -> Int -- ^ y-coordinate of the tile to be queried.+  -> m Integer -- ^ Color of the background of the cell.+terminalPickBkColor x y = liftIO $ fromIntegral <$> c_terminal_pick_bkcolor (fromIntegral x) (fromIntegral y)++-- | Draw a single character (given by its code point) onto the screen on the currently selected layer+-- with the currently selected colors and with additional options.+-- This takes an `Int` rather than `Char` to avoid possible headaches+-- with mismatching character codes over string conversion. If you know you are wanting to render single+-- *characters* (rather than *code points*), consider using `terminalPrintText` (or similar) instead.+--+-- Wrapper around [@terminal_put@](http://foo.wyrd.name/en:bearlibterminal:reference#put_ext)+terminalPutExt ::+  MonadIO m+  => Int -- ^ x-coordinate to print the character to.+  -> Int -- ^ y-coordinate to print the character to.+  -> Int -- ^ Internal x offset relative to the normal position of a tile in the cell, in pixels.+  -> Int -- ^ Internal y offset relative to the normal position of a tile in the cell, in pixels.+  -> Int -- ^ Unicode code point of the character to print.+  -> Maybe (Integer, Integer, Integer, Integer) -- ^ individual colours specified per-corner for this+  -- tile (in order: top-left, bottom-left, bottom-right, top-right)+  -> m ()+terminalPutExt x y dx dy code mbColors = liftIO $ colorsToArr $ c_terminal_put_ext (fromIntegral x) (fromIntegral y) (fromIntegral dx) (fromIntegral dy) (fromIntegral code)+  where+    colorsToArr :: (Ptr CUInt -> IO a) -> IO a+    colorsToArr f = case mbColors of+      Nothing -> f nullPtr+      Just (tl, bl, br, tr) -> withArray (map fromIntegral [tl, bl, br, tr]) f++-- | Measure the size of a string *if it were to be printed to the screen*, given as a `Text`.+-- Wrapper around [@terminal_measure@](http://foo.wyrd.name/en:bearlibterminal:reference#measure)+terminalMeasureText ::+  MonadIO m+  => Text -- ^ the string to measure the print for.+  -> m Dimensions -- ^ the size of the string if it were printed to the screen.+terminalMeasureText = textToCString terminalMeasureCString++-- | Measure the size of a string *if it were to be printed to the screen*, autowrapped in a bounding box, given as a `Text`.+-- Wrapper around [@terminal_measure_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#measure)+terminalMeasureExtText ::+  MonadIO m+  => Int -- ^ the width of the bounding box.+  -> Int -- ^ the height of the bounding box.+  -> Text  -- ^ the string to measure the print for.+  -> m Dimensions -- ^ the size of the string if it were printed to the screen.+terminalMeasureExtText w h = textToCString (terminalMeasureExtCString w h)++-- | This function queries the current numeric value of a library property; e.g. mouse position or clicks, or key presses/releases.+-- When looking to query for key presses or releases, `terminalKeyState` provides a better interface.+-- Wrapper around [@terminal_state@]. For more information, check the table in the original documentation:+-- http://foo.wyrd.name/en:bearlibterminal:reference:input#event_and_state_constants+terminalState :: MonadIO m => Keycode -> m Int+terminalState = liftIO . fmap fromIntegral . c_terminal_state . fromIntegral++-- | Returns true if there are currently input events in the input queue.+  -- Wrapper around [@terminal_measure_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#has_input)+terminalHasInput ::+  MonadIO m+  => m Bool -- ^ if there are currently input events in the input queue.+terminalHasInput = liftIO $ asBool <$> c_terminal_has_input++-- | Read an event from the input queue and remove it. If there are no pending events in the input queue, block+-- until there is. If you don't want to block until an event comes, check for input with `terminalHasInput` first.+-- This will return a raw integer - prefer `terminalPeek` to be able to use the pattern synonyms of named keycodes.+-- Wrapper around [@terminal_read@](http://foo.wyrd.name/en:bearlibterminal:reference#read).+-- For more information on the input queue, see the original documentation: http://foo.wyrd.name/en:bearlibterminal:reference:input#input_queue+terminalReadCode :: MonadIO m => m Int+terminalReadCode = liftIO $ fromIntegral <$> c_terminal_read++-- | Read an event from the input queue but **do not** remove it. If there are no pending events in the input queue, this will return `Nothing`.+-- This is non-blocking. This will return a raw integer - prefer `terminalPeek` to be able to use the pattern synonyms of named keycodes.+-- Wrapper around [@terminal_peek@](http://foo.wyrd.name/en:bearlibterminal:reference#peek).+-- For more information on the input queue, see the original documentation: http://foo.wyrd.name/en:bearlibterminal:reference:input#input_queue+terminalPeekCode :: MonadIO m => m Int+terminalPeekCode = liftIO $ fromIntegral <$> c_terminal_peek++-- | Read an inputted string and print a text input prompt at the given location.+-- This will block until the string is submitted (with Enter) or cancelled out (with Esc).+-- The string can be up to `maxStringReadSizeInBytes` bytes long.+-- Retyrns nothing if there was an error, or if the user cancelled out.+  -- Wrapper around [@terminal_measure_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#read_str)+terminalReadString ::+  MonadIO m+  => Int -- ^ x-coord of where the user input is displayed.+  -> Int -- ^ y-coord of where the user input is displayed.+  -> Int -- ^ max string length allowed (for the user, not for technical reasons).+  -> m (Maybe Text)+terminalReadString x y m = liftIO $ bracket+  (callocBytes maxStringReadSizeInBytes)+  free+  (\p -> do+    res <- c_read_str (fromIntegral x) (fromIntegral y) p (fromIntegral m)+    if res == -1 || res == 0 then return Nothing else+        (do+          t <- T.peekCStringLen (p, fromIntegral res)+          return (Just t)) `catch` (\(SomeException _) -> return Nothing)+  )+-- | Pause execution for a number of milliseconds.+-- Wrapper around [@terminal_measure_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#delay)+terminalDelay ::+  MonadIO m+  => Int -- ^ amount of time to suspend program execution for, in milliseconds.+  -> m ()+terminalDelay = liftIO . c_terminal_delay . fromIntegral++-- | Read an event from the input queue and remove it. If there are no pending events in the input queue, block+-- until there is. If you don't want to block until an event comes, check for input with `terminalHasInput` first.+-- Wrapper around [@terminal_read@](http://foo.wyrd.name/en:bearlibterminal:reference#read).+-- For more information on the input queue, see the original documentation: http://foo.wyrd.name/en:bearlibterminal:reference:input#input_queue+terminalRead :: MonadIO m => m Keycode+terminalRead = Keycode <$> terminalReadCode++-- | Read an event from the input queue but **do not** remove it. If there are no pending events in the input queue, this will return `Nothing`.+-- This is non-blocking.+-- Wrapper around [@terminal_peek@](http://foo.wyrd.name/en:bearlibterminal:reference#peek).+-- For more information on the input queue, see the original documentation: http://foo.wyrd.name/en:bearlibterminal:reference:input#input_queue+terminalPeek :: MonadIO m => m (Maybe Keycode)+terminalPeek = (\x -> if x == 0 then Nothing else Just (Keycode x)) <$> terminalPeekCode++-- | Get the current status of a key (e.g. pressed or released). This is a more specific version of `terminalState` for when the `Keycode` is+-- a keyboard key. The behaviour will be strange if you use this for e.g. querying the mouse position. Use `terminalState` for that.+-- Wrapper around [@terminal_state@](http://foo.wyrd.name/en:bearlibterminal:reference:input#state).+terminalKeyState :: MonadIO m => Keycode -> m Bool+terminalKeyState = fmap (== 1) . terminalState . coerce
+ src/BearLibTerminal/Keycodes.hs view
@@ -0,0 +1,406 @@+{-|+Module      : BearLibTerminal.Keycodes+Description : Keycodes and events.+License     : MIT+Stability   : experimental+Portability : POSIX++All events and keycodes that can be received by polling or queried for in the window state.+-}++{-# LANGUAGE PatternSynonyms #-}++module BearLibTerminal.Keycodes where++import GHC.Generics++-- | Events and states are defined in the original library as integer constants, which are all called keycodes. This is a very liberal+-- use of a "virtual keycode", because many of them are not keys.+-- These are defined as bidirectional pattern synonyms so that they still can be treated as bitwise operable (e.g. checking for key release+-- events).+-- These are used for:+-- - `BearLibTerminal.terminalRead` - polling for events (key presses, key releases, window events, mouse movements)+-- - `BearLibTerminal.terminalState` and `BearLibTerminal.terminalKeyState` - for querying current window state (e.g. mouse position) and+-- the status of whether keys are currently pressed respectively.+-- For full reference of the input queue, see http://foo.wyrd.name/en:bearlibterminal:reference:input.+newtype Keycode = Keycode Int+  deriving newtype (Eq, Ord, Show, Enum, Bounded, Num, Real, Integral)+  deriving stock (Generic)++pattern TkA :: Keycode+pattern TkA= Keycode 0x04++pattern TkB :: Keycode+pattern TkB= Keycode 0x05++pattern TkC :: Keycode+pattern TkC= Keycode 0x06++pattern TkD :: Keycode+pattern TkD= Keycode 0x07++pattern TkE :: Keycode+pattern TkE= Keycode 0x08++pattern TkF :: Keycode+pattern TkF= Keycode 0x09++pattern TkG :: Keycode+pattern TkG= Keycode 0x0A++pattern TkH :: Keycode+pattern TkH= Keycode 0x0B++pattern TkI :: Keycode+pattern TkI= Keycode 0x0C++pattern TkJ :: Keycode+pattern TkJ= Keycode 0x0D++pattern TkK :: Keycode+pattern TkK= Keycode 0x0E++pattern TkL :: Keycode+pattern TkL= Keycode 0x0F++pattern TkM :: Keycode+pattern TkM= Keycode 0x10++pattern TkN :: Keycode+pattern TkN= Keycode 0x11++pattern TkO :: Keycode+pattern TkO= Keycode 0x12++pattern TkP :: Keycode+pattern TkP= Keycode 0x13++pattern TkQ :: Keycode+pattern TkQ= Keycode 0x14++pattern TkR :: Keycode+pattern TkR= Keycode 0x15++pattern TkS :: Keycode+pattern TkS= Keycode 0x16++pattern TkT :: Keycode+pattern TkT= Keycode 0x17++pattern TkU :: Keycode+pattern TkU= Keycode 0x18++pattern TkV :: Keycode+pattern TkV= Keycode 0x19++pattern TkW :: Keycode+pattern TkW= Keycode 0x1A++pattern TkX :: Keycode+pattern TkX= Keycode 0x1B++pattern TkY :: Keycode+pattern TkY= Keycode 0x1C++pattern TkZ :: Keycode+pattern TkZ= Keycode 0x1D++pattern Tk1 :: Keycode+pattern Tk1= Keycode 0x1E++pattern Tk2 :: Keycode+pattern Tk2= Keycode 0x1F++pattern Tk3 :: Keycode+pattern Tk3= Keycode 0x20++pattern Tk4 :: Keycode+pattern Tk4= Keycode 0x21++pattern Tk5 :: Keycode+pattern Tk5= Keycode 0x22++pattern Tk6 :: Keycode+pattern Tk6= Keycode 0x23++pattern Tk7 :: Keycode+pattern Tk7= Keycode 0x24++pattern Tk8 :: Keycode+pattern Tk8= Keycode 0x25++pattern Tk9 :: Keycode+pattern Tk9= Keycode 0x26++pattern Tk0 :: Keycode+pattern Tk0= Keycode 0x27++pattern TkReturn :: Keycode+pattern TkReturn= Keycode 0x28++pattern TkEnter :: Keycode+pattern TkEnter= Keycode 0x28++pattern TkEscape :: Keycode+pattern TkEscape= Keycode 0x29++pattern TkBackspace :: Keycode+pattern TkBackspace= Keycode 0x2A++pattern TkTab :: Keycode+pattern TkTab= Keycode 0x2B++pattern TkSpace :: Keycode+pattern TkSpace= Keycode 0x2C++pattern TkMinus :: Keycode+pattern TkMinus= Keycode 0x2D++pattern TkEquals :: Keycode+pattern TkEquals= Keycode 0x2E++pattern TkLbracket :: Keycode+pattern TkLbracket= Keycode 0x2F++pattern TkRbracket :: Keycode+pattern TkRbracket= Keycode 0x30++pattern TkBackslash :: Keycode+pattern TkBackslash= Keycode 0x31++pattern TkSemicolon :: Keycode+pattern TkSemicolon= Keycode 0x33++pattern TkApostrophe :: Keycode+pattern TkApostrophe= Keycode 0x34++pattern TkGrave :: Keycode+pattern TkGrave= Keycode 0x35++pattern TkComma :: Keycode+pattern TkComma= Keycode 0x36++pattern TkPeriod :: Keycode+pattern TkPeriod= Keycode 0x37++pattern TkSlash :: Keycode+pattern TkSlash= Keycode 0x38++pattern TkF1 :: Keycode+pattern TkF1= Keycode 0x3A++pattern TkF2 :: Keycode+pattern TkF2= Keycode 0x3B++pattern TkF3 :: Keycode+pattern TkF3= Keycode 0x3C++pattern TkF4 :: Keycode+pattern TkF4= Keycode 0x3D++pattern TkF5 :: Keycode+pattern TkF5= Keycode 0x3E++pattern TkF6 :: Keycode+pattern TkF6= Keycode 0x3F++pattern TkF7 :: Keycode+pattern TkF7= Keycode 0x40++pattern TkF8 :: Keycode+pattern TkF8= Keycode 0x41++pattern TkF9 :: Keycode+pattern TkF9= Keycode 0x42++pattern TkF10 :: Keycode+pattern TkF10= Keycode 0x43++pattern TkF11 :: Keycode+pattern TkF11= Keycode 0x44++pattern TkF12 :: Keycode+pattern TkF12= Keycode 0x45++pattern TkPause :: Keycode+pattern TkPause= Keycode 0x48++pattern TkInsert :: Keycode+pattern TkInsert= Keycode 0x49++pattern TkHome :: Keycode+pattern TkHome= Keycode 0x4A++pattern TkPageup :: Keycode+pattern TkPageup= Keycode 0x4B++pattern TkDelete :: Keycode+pattern TkDelete= Keycode 0x4C++pattern TkEnd :: Keycode+pattern TkEnd= Keycode 0x4D++pattern TkPagedown :: Keycode+pattern TkPagedown= Keycode 0x4E++pattern TkRight :: Keycode+pattern TkRight= Keycode 0x4F++pattern TkLeft :: Keycode+pattern TkLeft= Keycode 0x50++pattern TkDown :: Keycode+pattern TkDown= Keycode 0x51++pattern TkUp :: Keycode+pattern TkUp= Keycode 0x52++pattern TkKpDivide :: Keycode+pattern TkKpDivide= Keycode 0x54++pattern TkKpMultiply :: Keycode+pattern TkKpMultiply= Keycode 0x55++pattern TkKpMinus :: Keycode+pattern TkKpMinus= Keycode 0x56++pattern TkKpPlus :: Keycode+pattern TkKpPlus= Keycode 0x57++pattern TkKpEnter :: Keycode+pattern TkKpEnter= Keycode 0x58++pattern TkKp1 :: Keycode+pattern TkKp1= Keycode 0x59++pattern TkKp2 :: Keycode+pattern TkKp2= Keycode 0x5A++pattern TkKp3 :: Keycode+pattern TkKp3= Keycode 0x5B++pattern TkKp4 :: Keycode+pattern TkKp4= Keycode 0x5C++pattern TkKp5 :: Keycode+pattern TkKp5= Keycode 0x5D++pattern TkKp6 :: Keycode+pattern TkKp6= Keycode 0x5E++pattern TkKp7 :: Keycode+pattern TkKp7= Keycode 0x5F++pattern TkKp8 :: Keycode+pattern TkKp8= Keycode 0x60++pattern TkKp9 :: Keycode+pattern TkKp9= Keycode 0x61++pattern TkKp0 :: Keycode+pattern TkKp0= Keycode 0x62++pattern TkKpPeriod :: Keycode+pattern TkKpPeriod= Keycode 0x63++pattern TkShift :: Keycode+pattern TkShift= Keycode 0x70++pattern TkControl :: Keycode+pattern TkControl= Keycode 0x71++pattern TkAlt :: Keycode+pattern TkAlt= Keycode 0x72++pattern TkMouseLeft :: Keycode+pattern TkMouseLeft= Keycode 0x80++pattern TkMouseRight :: Keycode+pattern TkMouseRight= Keycode 0x81++pattern TkMouseMiddle :: Keycode+pattern TkMouseMiddle= Keycode 0x82++pattern TkMouseX1 :: Keycode+pattern TkMouseX1= Keycode 0x83++pattern TkMouseX2 :: Keycode+pattern TkMouseX2= Keycode 0x84++pattern TkMouseMove :: Keycode+pattern TkMouseMove= Keycode 0x85++pattern TkMouseScroll :: Keycode+pattern TkMouseScroll= Keycode 0x86++pattern TkMouseX :: Keycode+pattern TkMouseX= Keycode 0x87++pattern TkMouseY :: Keycode+pattern TkMouseY= Keycode 0x88++pattern TkMousePixelX :: Keycode+pattern TkMousePixelX= Keycode 0x89++pattern TkMousePixelY :: Keycode+pattern TkMousePixelY= Keycode 0x8A++pattern TkMouseWheel :: Keycode+pattern TkMouseWheel= Keycode 0x8B++pattern TkMouseClicks :: Keycode+pattern TkMouseClicks= Keycode 0x8C++{-+ * If key was released instead of pressed, it's code will be OR'ed with TkKEYRELEASED:+ * a) pressed 'A' :: 0x04+ * b) released 'A' :: 0x04|VKKEYRELEASED == Keycode 0x104+-}+pattern TkKeyReleased :: Keycode+pattern TkKeyReleased = Keycode 0x100++{-+ * Virtual key-codes for internal terminal states/variables.+ * These can be accessed via terminalstate function.+-}+pattern TkWidth :: Keycode+pattern TkWidth= Keycode 0xC0++pattern TkHeight :: Keycode+pattern TkHeight= Keycode 0xC1++pattern TkCellWidth :: Keycode+pattern TkCellWidth= Keycode 0xC2++pattern TkCellHeight :: Keycode+pattern TkCellHeight= Keycode 0xC3++pattern TkColor :: Keycode+pattern TkColor= Keycode 0xC4++pattern TkBkcolor :: Keycode+pattern TkBkcolor= Keycode 0xC5++pattern TkLayer :: Keycode+pattern TkLayer= Keycode 0xC6++pattern TkComposition :: Keycode+pattern TkComposition= Keycode 0xC7++pattern TkChar :: Keycode+pattern TkChar= Keycode 0xC8++pattern TkWchar :: Keycode+pattern TkWchar= Keycode 0xC9++pattern TkEvent :: Keycode+pattern TkEvent= Keycode 0xCA++pattern TkFullscreen :: Keycode+pattern TkFullscreen= Keycode 0xCB++pattern TkClose :: Keycode+pattern TkClose= Keycode 0xE0++pattern TkResized :: Keycode+pattern TkResized= Keycode 0xE1
+ src/BearLibTerminal/Raw.hs view
@@ -0,0 +1,121 @@+{-|+Module      : BearLibTerminal.Raw+Description : Raw bindings to the BearLibTerminal C graphics library.+License     : MIT+Stability   : experimental+Portability : POSIX++These are the raw bindings to the C library. Not recommended to use them unless you really want to.+-}++{-# LANGUAGE CApiFFI #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE DuplicateRecordFields #-}++module BearLibTerminal.Raw where++import Foreign.C.Types+import Foreign.C.String+import Foreign.Ptr+import Foreign.Storable+import Control.Monad.IO.Class+import Data.Text (Text)+import qualified Data.Text.Foreign as TF+import GHC.Generics++-- | A 2D vector representing the dimensions of a string when printed to the screen (optionally with some auto string-wrapping).+data Dimensions = Dimensions+  { width :: Int+  , height :: Int+  } deriving stock (Show, Generic, Eq, Ord, Read)++instance Storable Dimensions where+  sizeOf _ = 8+  alignment _ = 4+  poke p Dimensions{..} = do+    pokeByteOff p 0 width+    pokeByteOff p 4 height+  peek p = do+    (width :: CUInt) <- peekByteOff p 0+    (height :: CUInt) <- peekByteOff p 4+    return $ Dimensions (fromIntegral width) (fromIntegral height)++-- | Alignment of glyphs within a cell. Primarily useful for alignment of multi-cell characters.+data PrintAlignment = AlignDefault | AlignLeft | AlignRight | AlignCenter | AlignTop | AlignBottom | AlignMiddle+  deriving stock (Eq, Ord, Bounded, Enum, Generic, Show, Read)++-- | Wrap a C TRUE return value into a Haskell boolean.+asBool :: CInt -> Bool+asBool = (== 1)++foreign import capi safe "BearLibTerminal.h terminal_open" c_terminal_open :: IO CInt++foreign import capi safe "BearLibTerminal.h terminal_close" c_terminal_close :: IO ()++foreign import capi safe "BearLibTerminal.h terminal_set" c_terminal_set :: CString -> IO CInt++textToCString :: MonadIO m => (CString -> IO a) -> Text -> m a+textToCString f = liftIO . flip TF.withCString f++stringToCString :: MonadIO m => (CString -> IO a) -> String -> m a+stringToCString f = liftIO . flip withCString f++-- | prepend and amend semigroups.+surround :: Semigroup a => a -> a -> a -> a+surround p s t = p <> t <> s++foreign import capi safe "BearLibTerminal.h terminal_color" c_terminal_color_uint :: CUInt -> IO ()+foreign import capi safe "BearLibTerminalExtras.h terminal_color_from_name" c_terminal_color_from_name :: CString -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_bkcolor" c_terminal_bkcolor_uint :: CUInt -> IO ()+foreign import capi safe "BearLibTerminalExtras.h terminal_bkcolor_from_name" c_terminal_bkcolor_from_name :: CString -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_composition" c_terminal_composition :: CInt -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_layer" c_terminal_layer :: CInt -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_clear" c_terminal_clear :: IO ()++foreign import capi safe "BearLibTerminal.h terminal_clear_area" c_terminal_clear_area :: CInt -> CInt -> CInt -> CInt -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_crop" c_terminal_crop :: CInt -> CInt -> CInt -> CInt -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_refresh" c_terminal_refresh :: IO ()++foreign import capi safe "BearLibTerminal.h terminal_put" c_terminal_put :: CInt -> CInt -> CInt -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_pick" c_terminal_pick :: CInt -> CInt -> CInt -> IO CInt++foreign import capi safe "BearLibTerminal.h terminal_pick_color" c_terminal_pick_color :: CInt -> CInt -> CInt -> IO CUInt++foreign import capi safe "BearLibTerminal.h terminal_pick_bkcolor" c_terminal_pick_bkcolor :: CInt -> CInt -> IO CUInt++foreign import capi safe "BearLibTerminal.h terminal_put_ext" c_terminal_put_ext :: CInt -> CInt -> CInt -> CInt -> CInt -> Ptr CUInt -> IO ()++foreign import capi safe "BearLibTerminalExtras.h terminal_print_ptr" c_terminal_print_ptr :: CInt -> CInt -> CString -> Ptr Dimensions -> IO ()++foreign import capi safe "BearLibTerminalExtras.h terminal_print_ext_ptr" c_terminal_print_ext_ptr :: CInt -> CInt -> CInt -> CInt -> CInt -> CString -> Ptr Dimensions -> IO ()++-- I don't know if wchar is actually useful here.+-- I don't care enough to try and wrap va_list around the printf variants.+-- so that's printf, printf_ext, wprint, wprintf, wprint_ext, wprintf_ext, measuref, wmeasure, measuref_ext, wmeasuref_ext+-- check is unnecessary+-- foreign import capi unsafe "BearLibTerminal.h terminal_check" c_terminal_check :: CInt -> IO CInt+-- also read_wstr+-- not bothering with: color_from_name, color_from_argb++foreign import capi safe "BearLibTerminalExtras.h terminal_measure_ptr" c_terminal_measure_ptr :: CString -> Ptr Dimensions -> IO ()++foreign import capi safe "BearLibTerminalExtras.h terminal_measure_ext_ptr" c_terminal_measure_ext_ptr :: CInt -> CInt -> CString -> Ptr Dimensions -> IO ()++foreign import capi safe "BearLibTerminal.h terminal_state" c_terminal_state :: CInt -> IO CInt++foreign import capi safe "BearLibTerminal.h terminal_has_input" c_terminal_has_input :: IO CInt++foreign import capi safe "BearLibTerminal.h terminal_read" c_terminal_read :: IO CInt++foreign import capi safe "BearLibTerminal.h terminal_peek" c_terminal_peek :: IO CInt++foreign import capi safe "BearLibTerminal.h terminal_read_str" c_read_str :: CInt -> CInt -> Ptr CChar -> CInt -> IO CUInt++foreign import capi safe "BearLibTerminal.h terminal_delay" c_terminal_delay :: CInt -> IO ()
+ src/BearLibTerminal/Terminal/CString.hs view
@@ -0,0 +1,131 @@+{-|+Module      : BearLibTerminal.Terminal.CString+Description : String functions taking `CString`s.+License     : MIT+Stability   : experimental+Portability : POSIX++Functions that take strings as `CString`s. Unless you are wanting to marshall across the foreign boundary yourself,+you probably don't want to use these (prefer `Data.Text.Text` from `BearLibTerminal` or `String` from `BearLibTerminal.Terminal.String`).+-}++module BearLibTerminal.Terminal.CString+  ( terminalSetCString+  , terminalSetCString_+  , terminalColorNameCString+  , terminalBkColorNameCString++  , terminalPrintCString+  , terminalPrintExtCString++  , terminalMeasureCString+  , terminalMeasureExtCString++  ) where++import BearLibTerminal.Raw+import Control.Monad.IO.Class+import Data.Function ((&))+import Data.Maybe (fromMaybe)+import Foreign+import Foreign.C.String+import Foreign.C.Types (CInt)++-- | Set one or more of the configuration options, given as a `CString`.+--+-- Wrapper around [@terminal_set@](http://foo.wyrd.name/en:bearlibterminal:reference).+-- More details are available at the BearLibTerminal docs: http://foo.wyrd.name/en:bearlibterminal:reference:configuration.+terminalSetCString :: MonadIO m =>+  CString -- ^ Configuration string.+  -> m Bool -- ^ whether the configuration was successful.+terminalSetCString = liftIO . (fmap asBool . c_terminal_set)++-- | Set one or more of the configuration options, given as a `CString`. Ignore if it was successful.+--+-- Wrapper around [@terminal_set@](http://foo.wyrd.name/en:bearlibterminal:reference).+-- More details are available at the BearLibTerminal docs: http://foo.wyrd.name/en:bearlibterminal:reference:configuration.+terminalSetCString_ :: MonadIO m =>+  CString -- ^ Configuration string.+  -> m ()+terminalSetCString_ = liftIO . (void . c_terminal_set)++-- | Set the currently selected foreground color to be used by following output functions (e.g. `terminalPrintText`).+-- Takes a color as a name in a variety of formats; see [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name)+-- for a full list.+--+-- Takes the color name as a `CString`.+--+-- Wrapper around [@terminal_color@](http://foo.wyrd.name/en:bearlibterminal:reference#color) and+-- [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name).+terminalColorNameCString ::+  MonadIO m+  => CString  -- ^ the color name to be selected, in @"[brightness]hue"@ format as specified in @color_from_name@.+  -> m ()+terminalColorNameCString = liftIO . c_terminal_color_from_name++-- | Set the currently selected foreground color to be used by following output functions (e.g. `terminalPrintText`).+-- Takes a color as a name in a variety of formats; see [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name)+-- for a full list.+--+-- Takes the color name as a `CString`.+--+-- Wrapper around [@terminal_bkcolor@](http://foo.wyrd.name/en:bearlibterminal:reference#bkcolor) and+-- [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name).+terminalBkColorNameCString ::+  MonadIO m+  => CString  -- ^ the color name to be selected, in @"[brightness]hue"@ format as specified in @color_from_name@.+  -> m ()+terminalBkColorNameCString = liftIO . c_terminal_bkcolor_from_name++-- | Print a string to the screen, given as a `CString`.+--+-- Wrapper around [@terminal_print@](http://foo.wyrd.name/en:bearlibterminal:reference#print).+terminalPrintCString ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> CString -- ^ the string to print.+  -> m Dimensions -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintCString x y c = liftIO $ alloca (\dim -> c_terminal_print_ptr (fromIntegral x) (fromIntegral y) c dim >> peek dim)++-- | Print a string to the screen, given as a `CString`, with (optional) auto-wrapping and alignment.+-- Wrapper around [@terminal_print_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#print_ext)+terminalPrintExtCString ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Int -- ^ width of the bounding box for auto-wrapping and alignment.+  -> Int -- ^ height of the bounding box for auto-wrapping and alignment.+  -> Maybe PrintAlignment -- ^ alignment of the string within the bounding box.+  -> CString -- ^ the string to print.+  -> m Dimensions -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintExtCString x y w h mbAlign c =+  let align :: CInt+      align = fromMaybe AlignDefault mbAlign & \case+        AlignDefault -> 0+        AlignLeft -> 1+        AlignRight -> 2+        AlignCenter -> 3+        AlignTop -> 4+        AlignBottom -> 8+        AlignMiddle -> 12+  in+  liftIO $ alloca (\dim -> c_terminal_print_ext_ptr (fromIntegral x) (fromIntegral y) (fromIntegral w) (fromIntegral h) align c dim >> peek dim)++-- | Measure the size of a string *if it were to be printed to the screen*, given as a `CString`.+-- Wrapper around [@terminal_measure@](http://foo.wyrd.name/en:bearlibterminal:reference#measure)+terminalMeasureCString ::+  MonadIO m+  => CString -- ^ the string to measure the print for.+  -> m Dimensions -- ^ the size of the string if it were printed to the screen.+terminalMeasureCString c = liftIO $ alloca (\dim -> c_terminal_measure_ptr c dim >> peek dim)++-- | Measure the size of a string *if it were to be printed to the screen*, autowrapped in a bounding box, given as a `CString`.+-- Wrapper around [@terminal_measure_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#measure)+terminalMeasureExtCString ::+  MonadIO m+  => Int -- ^ the width of the bounding box.+  -> Int -- ^ the height of the bounding box.+  -> CString  -- ^ the string to measure the print for.+  -> m Dimensions -- ^ the size of the string if it were printed to the screen.+terminalMeasureExtCString w h c = liftIO $ alloca (\dim -> c_terminal_measure_ext_ptr (fromIntegral w) (fromIntegral h) c dim >> peek dim)
+ src/BearLibTerminal/Terminal/Color.hs view
@@ -0,0 +1,90 @@+{-|+Module      : BearLibTerminal.Terminal.Color+Description : Color functions.+License     : MIT+Stability   : experimental+Portability : POSIX++Setting the active foreground/background colors and a couple of helper functions for making colors from (A)RGB quads/triples.+-}++module BearLibTerminal.Terminal.Color+  ( colorFromARGB+  , colorFromRGB+  , terminalColorUInt+  , terminalColorName+  , terminalBkColorUInt+  , terminalBkColorName+  ) where++import Control.Monad.IO.Class+import Data.Text+import BearLibTerminal.Raw+import BearLibTerminal.Terminal.CString+import Data.Bits++-- | Convert a color given as 4 integer values (0-255) into an unsigned integer for use with `terminalColorUInt`. No bounds checking is performed.+colorFromARGB ::+  Integral a+  => a -- ^ alpha channel value.+  -> a -- ^ red channel value.+  -> a -- ^ green channel value.+  -> a -- ^ blue channel value.+  -> Int -- ^ color in 32-bit integer form.+colorFromARGB a r g b = (fromIntegral a `shiftL` 24) .|. (fromIntegral r `shiftL` 16) .|. (fromIntegral g `shiftL` 8) .|. fromIntegral b++-- | Convert a color given as 3 integer values (0-255) into an unsigned integer for use with `terminalColorUInt`. No bounds checking is performed.+-- The alpha channel is fully opaque (0xFF).+colorFromRGB ::+  Integral a+  => a -- ^ red channel value.+  -> a -- ^ green channel value.+  -> a -- ^ blue channel value.+  -> Int -- ^ color in 32-bit integer form.+colorFromRGB = colorFromARGB 255++-- | Set the currently selected foreground color to be used by following output functions (e.g. print).+-- Takes a color as a 32-bit unsigned integer in ARGB format.+-- Wrapper around [@terminal_color@](http://foo.wyrd.name/en:bearlibterminal:reference#color).+terminalColorUInt ::+  MonadIO m+  => Int -- ^ the color to set in 32-bit ARGB format.+  -> m ()+terminalColorUInt = liftIO . c_terminal_color_uint . fromIntegral++-- | Set the currently selected foreground color to be used by following output functions (e.g. `terminalPrintText`).+-- Takes a color as a name in a variety of formats; see [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name)+-- for a full list.+--+-- Takes the color name as a `Text`.+--+-- Wrapper around [@terminal_color@](http://foo.wyrd.name/en:bearlibterminal:reference#color) and+-- [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name).+terminalColorName ::+  MonadIO m+  => Text -- ^ the color name to be selected,in @"[brightness]hue"@ format as specified in @color_from_name@.+  -> m ()+terminalColorName = textToCString terminalColorNameCString++-- | Set the currently selected background color to be used by following output functions (e.g. print).+-- Takes a color as a 32-bit unsigned integer in ARGB format.+-- Wrapper around [@terminal_bkcolor@](http://foo.wyrd.name/en:bearlibterminal:reference#bkcolor).+terminalBkColorUInt ::+  MonadIO m+  => Int -- ^ the color to set in 32-bit ARGB format.+  -> m ()+terminalBkColorUInt = liftIO . c_terminal_bkcolor_uint . fromIntegral++-- | Set the currently selected background color to be used by following output functions (e.g. `terminalPrintText`).+-- Takes a color as a name in a variety of formats; see [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name)+-- for a full list.+--+-- Takes the color name as a `Text`.+--+-- Wrapper around [@terminal_bkcolor@](http://foo.wyrd.name/en:bearlibterminal:reference#bkcolor) and+-- [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name).+terminalBkColorName ::+  MonadIO m+  => Text -- ^ the color name to be selected, in @"[brightness]hue"@ format as specified in @color_from_name@.+  -> m ()+terminalBkColorName = textToCString terminalBkColorNameCString
+ src/BearLibTerminal/Terminal/Print.hs view
@@ -0,0 +1,94 @@+{-|+Module      : BearLibTerminal.Terminal.Print+Description : Printing text.+License     : MIT+Stability   : experimental+Portability : POSIX++Functions for printing text to the screen (given as `Data.Text.Text`), and a couple of helper functions for wrapping+strings with inline color strings.+-}++module BearLibTerminal.Terminal.Print+  ( textColor+  , textBkColor+  , terminalPrint+  , terminalPrint_+  , terminalPrintExt+  , terminalPrintExt_+  ) where++import BearLibTerminal.Raw+import Control.Monad.IO.Class++import Data.Text (Text)+import BearLibTerminal.Terminal.CString+import Data.String (IsString)+import Control.Monad (void)++-- | Wrap a string (in any `IsString` format) with color formatting tags.+textColor ::+  IsString a+  => Semigroup a+  => a -- ^ the color, from the list of valid color identifiers - http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name.+  -> a -- ^ the text to wrap.+  -> a+textColor col = surround ("[color="<>col<>"]") "[/color]"++-- | Wrap a string (in any `IsString` format) with background color formatting tags.+textBkColor ::+  IsString a+  => Semigroup a+  => a -- ^ the background color, from the list of valid color identifiers - http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name.+  -> a -- ^ the text to wrap.+  -> a+textBkColor col = surround ("[bkcolor="<>col<>"]") "[/bkcolor]"++-- | Print a string to the screen, given as a `Text`.+--+-- Wrapper around [@terminal_print@](http://foo.wyrd.name/en:bearlibterminal:reference#print).+terminalPrint ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Text -- ^ the string to print.+  -> m Dimensions -- ^ the `Dimensions` of the string as printed on screen.+terminalPrint x y = textToCString (terminalPrintCString x y)++-- | Print a string to the screen, given as a `Text`, with (optional) auto-wrapping and alignment.+-- Wrapper around [@terminal_print_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#print_ext)+terminalPrintExt ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Int -- ^ width of the bounding box for auto-wrapping and alignment.+  -> Int -- ^ height of the bounding box for auto-wrapping and alignment.+  -> Maybe PrintAlignment -- ^ alignment of the string within the bounding box.+  -> Text -- ^ the string to print.+  -> m Dimensions -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintExt x y w h align = textToCString (terminalPrintExtCString x y w h align)++-- | Print a string to the screen, given as a `Text`. Ignore the dimensions of the printed string.+--+-- Wrapper around [@terminal_print@](http://foo.wyrd.name/en:bearlibterminal:reference#print).+terminalPrint_ ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Text -- ^ the string to print.+  -> m ()+terminalPrint_ x y t = void $ terminalPrint x y t++-- | Print a string to the screen, given as a `Text`, with (optional) auto-wrapping and alignment.+-- gnore the dimensions of the printed string.+-- Wrapper around [@terminal_print_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#print_ext)+terminalPrintExt_ ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Int -- ^ width of the bounding box for auto-wrapping and alignment.+  -> Int -- ^ height of the bounding box for auto-wrapping and alignment.+  -> Maybe PrintAlignment -- ^ alignment of the string within the bounding box.+  -> Text -- ^ the string to print.+  -> m ()+terminalPrintExt_ x y w h align t = void $ terminalPrintExt x y w h align t
+ src/BearLibTerminal/Terminal/Set.hs view
@@ -0,0 +1,58 @@+{-|+Module      : BearLibTerminal.Terminal.Set+Description : Setting configuration options.+License     : MIT+Stability   : experimental+Portability : POSIX++Setting configuration options - e.g. cell size, fonts, window title, etc etc etc. A full list of everything settable is at+http://foo.wyrd.name/en:bearlibterminal:reference:configuration.++There are some helper functions specifically for setting a title, but it is recommended to use a @printf@ style package+to build longer configuration strings.+-}++module BearLibTerminal.Terminal.Set+  ( terminalSet+  , terminalSet_++  , terminalSetTitle+  , terminalSetMany+  ) where++import BearLibTerminal.Raw+import BearLibTerminal.Terminal.CString+import Control.Monad.IO.Class+import Data.Text (Text)+import qualified Data.Text as T++-- | Set one or more of the configuration options, given as a `Text`.+--+-- Wrapper around [@terminal_set@](http://foo.wyrd.name/en:bearlibterminal:reference).+-- More details are available at the BearLibTerminal docs: http://foo.wyrd.name/en:bearlibterminal:reference:configuration.+terminalSet :: MonadIO m =>+  Text -- ^ Configuration string.+  -> m Bool -- ^ whether the configuration was successful.+terminalSet = textToCString terminalSetCString++-- | Set one or more of the configuration options, given as a `Text`. Ignore if it was successful.+--+-- Wrapper around [@terminal_set@](http://foo.wyrd.name/en:bearlibterminal:reference).+-- More details are available at the BearLibTerminal docs: http://foo.wyrd.name/en:bearlibterminal:reference:configuration.+terminalSet_ ::+  MonadIO m+  => Text -- ^ Configuration string.+  -> m ()+terminalSet_ = textToCString terminalSetCString_++-- | Set the title of the window.+terminalSetTitle :: MonadIO m => Text -> m ()+terminalSetTitle = terminalSet_ . ("window: " <>) . surround "title='" "'"++-- | Set multiple properties at once under a specific super-heading.+terminalSetMany ::+  MonadIO m+  => Text -- ^ the super-heading to set things under (e.g. `window`)+  -> [Text] -- ^ the list of key:value properties to be set.+  -> m ()+terminalSetMany super rest = terminalSet_ $ super <> ": " <> T.intercalate ", " rest
+ src/BearLibTerminal/Terminal/String.hs view
@@ -0,0 +1,144 @@+{-|+Module      : BearLibTerminal.Terminal.String+Description : String functions taking `String`s.+License     : MIT+Stability   : experimental+Portability : POSIX++Functions that take strings as `String`s. It is preferable to use the `Data.Text.Text` versions if possible, but these are fine+too.+-}++module BearLibTerminal.Terminal.String+  ( terminalSetString+  , terminalSetString_+  , terminalColorNameString+  , terminalBkColorNameString+  , terminalPrintString+  , terminalPrintString_+  , terminalPrintExtString+  , terminalPrintExtString_++  , terminalMeasureString+  , terminalMeasureExtString++  ) where++import BearLibTerminal.Raw+import BearLibTerminal.Terminal.CString+import Control.Monad (void)+import Control.Monad.IO.Class++-- | Set one or more of the configuration options, given as a `String`.+--+-- Wrapper around [@terminal_set@](http://foo.wyrd.name/en:bearlibterminal:reference).+-- More details are available at the BearLibTerminal docs: http://foo.wyrd.name/en:bearlibterminal:reference:configuration.+terminalSetString :: MonadIO m =>+  String -- ^ Configuration string.+  -> m Bool -- ^ whether the configuration was successful.+terminalSetString = stringToCString terminalSetCString++-- | Set one or more of the configuration options, given as a `String`. Ignore if it was successful.+--+-- Wrapper around [@terminal_set@](http://foo.wyrd.name/en:bearlibterminal:reference).+-- More details are available at the BearLibTerminal docs: http://foo.wyrd.name/en:bearlibterminal:reference:configuration.+terminalSetString_ :: MonadIO m =>+  String -- ^ Configuration string.+  -> m ()+terminalSetString_ = stringToCString terminalSetCString_++-- | Set the currently selected foreground color to be used by following output functions (e.g. `terminalPrintText`).+-- Takes a color as a name in a variety of formats; see [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name)+-- for a full list.+--+-- Takes the color name as a `String`.+--+-- Wrapper around [@terminal_color@](http://foo.wyrd.name/en:bearlibterminal:reference#color) and+-- [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name).+terminalColorNameString ::+  MonadIO m+  => String  -- ^ the color name to be selected, in @"[brightness]hue"@ format as specified in @color_from_name@.+  -> m ()+terminalColorNameString = stringToCString terminalColorNameCString++-- | Set the currently selected background color to be used by following output functions (e.g. `terminalPrintText`).+-- Takes a color as a name in a variety of formats; see [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name)+-- for a full list.+--+-- Takes the color name as a `String`.+--+-- Wrapper around [@terminal_bkcolor@](http://foo.wyrd.name/en:bearlibterminal:reference#bkcolor) and+-- [@color_from_name@](http://foo.wyrd.name/en:bearlibterminal:reference#color_from_name).+terminalBkColorNameString ::+  MonadIO m+  => String  -- ^ the color name to be selected, in @"[brightness]hue"@ format as specified in @color_from_name@.+  -> m ()+terminalBkColorNameString = stringToCString terminalBkColorNameCString++-- | Print a string to the screen, given as a `String`.+--+-- Wrapper around [@terminal_print@](http://foo.wyrd.name/en:bearlibterminal:reference#print).+terminalPrintString ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> String -- ^ the string to print.+  -> m Dimensions -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintString x y = stringToCString (terminalPrintCString x y)++-- | Print a string to the screen, given as a `String`. Ignore the returned dimensions.+--+-- Wrapper around [@terminal_print@](http://foo.wyrd.name/en:bearlibterminal:reference#print).+terminalPrintString_ ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> String -- ^ the string to print.+  -> m () -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintString_ x y = void . terminalPrintString x y++-- | Print a string to the screen, given as a `String`, with (optional) auto-wrapping and alignment.+-- Wrapper around [@terminal_print_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#print_ext)+terminalPrintExtString ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Int -- ^ width of the bounding box for auto-wrapping and alignment.+  -> Int -- ^ height of the bounding box for auto-wrapping and alignment.+  -> Maybe PrintAlignment -- ^ alignment of the string within the bounding box.+  -> String -- ^ the string to print.+  -> m Dimensions -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintExtString x y w h align = stringToCString (terminalPrintExtCString x y w h align)++-- | Print a string to the screen, given as a `String`, with (optional) auto-wrapping and alignment.+-- Ignore the returned dimensions.+-- Wrapper around [@terminal_print_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#print_ext)+terminalPrintExtString_ ::+  MonadIO m+  => Int  -- ^ x-coordinate to start printing the string at.+  -> Int -- ^ y-coordinate to start printing the string at.+  -> Int -- ^ width of the bounding box for auto-wrapping and alignment.+  -> Int -- ^ height of the bounding box for auto-wrapping and alignment.+  -> Maybe PrintAlignment -- ^ alignment of the string within the bounding box.+  -> String -- ^ the string to print.+  -> m () -- ^ the `Dimensions` of the string as printed on screen.+terminalPrintExtString_ x y w h align = void . terminalPrintExtString x y w h align+++-- | Measure the size of a string *if it were to be printed to the screen*, given as a `String`.+-- Wrapper around [@terminal_measure@](http://foo.wyrd.name/en:bearlibterminal:reference#measure)+terminalMeasureString ::+  MonadIO m+  => String -- ^ the string to measure the print for.+  -> m Dimensions -- ^ the size of the string if it were printed to the screen.+terminalMeasureString = stringToCString terminalMeasureCString++-- | Measure the size of a string *if it were to be printed to the screen*, autowrapped in a bounding box, given as a `String`.+-- Wrapper around [@terminal_measure_ext@](http://foo.wyrd.name/en:bearlibterminal:reference#measure)+terminalMeasureExtString ::+  MonadIO m+  => Int -- ^ the width of the bounding box.+  -> Int -- ^ the height of the bounding box.+  -> String  -- ^ the string to measure the print for.+  -> m Dimensions -- ^ the size of the string if it were printed to the screen.+terminalMeasureExtString w h = stringToCString (terminalMeasureExtCString w h)