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 +86/−0
- cbits/BearLibTerminal.h +766/−0
- cbits/BearLibTerminalExtras.h +41/−0
- omni/Main.hs +82/−0
- omni/Omni/BasicOutput.hs +49/−0
- omni/Omni/DefaultFont.hs +125/−0
- omni/Omni/ManualCellsize.hs +70/−0
- omni/Omni/Tilesets.hs +59/−0
- src/BearLibTerminal.hs +407/−0
- src/BearLibTerminal/Keycodes.hs +406/−0
- src/BearLibTerminal/Raw.hs +121/−0
- src/BearLibTerminal/Terminal/CString.hs +131/−0
- src/BearLibTerminal/Terminal/Color.hs +90/−0
- src/BearLibTerminal/Terminal/Print.hs +94/−0
- src/BearLibTerminal/Terminal/Set.hs +58/−0
- src/BearLibTerminal/Terminal/String.hs +144/−0
+ 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)