Vendor raptor source files (was embedded gitlink)

Tree vendored at upstream 0019c5dd; origin + license recorded in
raptor/VENDOR.txt. Windows SDL dev packages excluded via .gitignore.
This commit is contained in:
raptorreplica committed 2026-08-25 22:08:42 +10:00
1 parent bd3ea30d55
commit f7c9b7a02d
809 files changed
+337824 -1

No files matched your search

@@ -0,0 +1,248 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="textscreen" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win (32 bit) Debug">
<Option platforms="Windows;" />
<Option output="bin/Debug/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/i686-w64-mingw32/include/SDL2" />
</Compiler>
<Linker>
<Add option="-lmingw32 -lSDL2main -lSDL2" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/i686-w64-mingw32/lib" />
</Linker>
</Target>
<Target title="Win (32 bit) Release">
<Option platforms="Windows;" />
<Option output="bin/Release/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/i686-w64-mingw32/include/SDL2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lmingw32 -lSDL2main -lSDL2" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/i686-w64-mingw32/lib" />
</Linker>
</Target>
<Target title="Linux (32 bit) Debug">
<Option platforms="Unix;" />
<Option output="bin/Debug/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-g" />
<Add directory="/usr/include/SDL2" />
</Compiler>
<Linker>
<Add option="-lSDL2main -lSDL2" />
<Add directory="/usr/lib32" />
</Linker>
</Target>
<Target title="Linux (32 bit) Release">
<Option platforms="Unix;" />
<Option output="bin/Release/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add directory="/usr/include/SDL2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-lSDL2main -lSDL2" />
<Add directory="/usr/lib32" />
</Linker>
</Target>
<Target title="Linux (64 bit) Debug">
<Option platforms="Unix;" />
<Option output="bin/Debug/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add directory="/usr/include/SDL2" />
</Compiler>
<Linker>
<Add option="-m64" />
<Add option="-lSDL2main -lSDL2" />
<Add directory="/usr/lib" />
</Linker>
</Target>
<Target title="Linux (64 bit) Release">
<Option platforms="Unix;" />
<Option output="bin/Release/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-m64" />
<Add directory="/usr/include/SDL2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
<Add option="-lSDL2main -lSDL2" />
<Add directory="/usr/lib" />
</Linker>
</Target>
<Target title="Win (64 bit) Debug">
<Option platforms="Windows;" />
<Option output="bin/Debug/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Debug/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/x86_64-w64-mingw32/include/SDL2" />
</Compiler>
<Linker>
<Add option="-m64" />
<Add option="-lmingw32 -lSDL2main -lSDL2" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/x86_64-w64-mingw32/lib" />
</Linker>
</Target>
<Target title="Win (64 bit) Release">
<Option platforms="Windows;" />
<Option output="bin/Release/textscreen" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="obj/Release/" />
<Option type="2" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O2" />
<Add option="-m64" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/x86_64-w64-mingw32/include/SDL2" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
<Add option="-lmingw32 -lSDL2main -lSDL2" />
<Add directory="../../SDL2-devel-2.28.2-mingw/SDL2-2.28.2/x86_64-w64-mingw32/lib" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-m32" />
<Add directory="../../SDL2-devel-2.0.14-mingw/SDL2-2.0.14/i686-w64-mingw32/include/SDL2" />
</Compiler>
<Linker>
<Add option="-m32" />
<Add directory="../../SDL2-devel-2.0.14-mingw/SDL2-2.0.14/i686-w64-mingw32/lib" />
</Linker>
<Unit filename="../include/doomkeys.h" />
<Unit filename="../include/textscreen.h" />
<Unit filename="../include/txt_button.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_button.h" />
<Unit filename="../include/txt_checkbox.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_checkbox.h" />
<Unit filename="../include/txt_conditional.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_conditional.h" />
<Unit filename="../include/txt_desktop.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_desktop.h" />
<Unit filename="../include/txt_dropdown.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_dropdown.h" />
<Unit filename="../include/txt_fileselect.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_fileselect.h" />
<Unit filename="../include/txt_gui.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_gui.h" />
<Unit filename="../include/txt_inputbox.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_inputbox.h" />
<Unit filename="../include/txt_io.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_io.h" />
<Unit filename="../include/txt_label.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_label.h" />
<Unit filename="../include/txt_main.h" />
<Unit filename="../include/txt_radiobutton.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_radiobutton.h" />
<Unit filename="../include/txt_scrollpane.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_scrollpane.h" />
<Unit filename="../include/txt_sdl.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_sdl.h" />
<Unit filename="../include/txt_separator.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_separator.h" />
<Unit filename="../include/txt_spinctrl.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_spinctrl.h" />
<Unit filename="../include/txt_strut.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_strut.h" />
<Unit filename="../include/txt_table.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_table.h" />
<Unit filename="../include/txt_utf8.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_utf8.h" />
<Unit filename="../include/txt_widget.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_widget.h" />
<Unit filename="../include/txt_window.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_window.h" />
<Unit filename="../include/txt_window_action.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../include/txt_window_action.h" />
<Extensions />
</Project>
</CodeBlocks_project_file>
@@ -0,0 +1,6 @@
Makefile
Makefile.in
.deps
*.a
tags
TAGS
@@ -0,0 +1,32 @@
add_library(textscreen STATIC
textscreen.h
txt_conditional.c txt_conditional.h
txt_checkbox.c txt_checkbox.h
txt_desktop.c txt_desktop.h
txt_dropdown.c txt_dropdown.h
txt_fileselect.c txt_fileselect.h
txt_gui.c txt_gui.h
txt_inputbox.c txt_inputbox.h
txt_io.c txt_io.h
txt_main.h
txt_button.c txt_button.h
txt_label.c txt_label.h
txt_radiobutton.c txt_radiobutton.h
txt_scrollpane.c txt_scrollpane.h
txt_separator.c txt_separator.h
txt_spinctrl.c txt_spinctrl.h
txt_sdl.c txt_sdl.h
txt_strut.c txt_strut.h
txt_table.c txt_table.h
txt_utf8.c txt_utf8.h
txt_widget.c txt_widget.h
txt_window.c txt_window.h
txt_window_action.c txt_window_action.h)
target_include_directories(textscreen
INTERFACE "."
PRIVATE "../src/")
if(MSVC)
target_link_libraries(textscreen SDL2::SDL2)
else()
target_link_libraries(textscreen m SDL2::SDL2)
endif()
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,41 @@
AM_CFLAGS = -I$(top_srcdir)/src
CTAGS_ARGS=-I TXT_UNCAST_ARG+
# build this directory before the examples directory.
SUBDIRS = fonts . examples
noinst_LIBRARIES=libtextscreen.a
EXTRA_DIST=CMakeLists.txt Doxyfile
libtextscreen_a_SOURCES = \
textscreen.h \
txt_conditional.c txt_conditional.h \
txt_checkbox.c txt_checkbox.h \
txt_desktop.c txt_desktop.h \
txt_dropdown.c txt_dropdown.h \
txt_fileselect.c txt_fileselect.h \
txt_gui.c txt_gui.h \
txt_inputbox.c txt_inputbox.h \
txt_io.c txt_io.h \
txt_main.h \
txt_button.c txt_button.h \
txt_label.c txt_label.h \
txt_radiobutton.c txt_radiobutton.h \
txt_scrollpane.c txt_scrollpane.h \
txt_separator.c txt_separator.h \
txt_spinctrl.c txt_spinctrl.h \
txt_sdl.c txt_sdl.h \
txt_strut.c txt_strut.h \
txt_table.c txt_table.h \
txt_utf8.c txt_utf8.h \
txt_widget.c txt_widget.h \
txt_window.c txt_window.h \
txt_window_action.c txt_window_action.h
doc:
doxygen
@@ -0,0 +1,154 @@
//
// Copyright(C) 1993-1996 Id Software, Inc.
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// DESCRIPTION:
// Key definitions
//
#ifndef __DOOMKEYS__
#define __DOOMKEYS__
//
// DOOM keyboard definition.
// This is the stuff configured by Setup.Exe.
// Most key data are simple ascii (uppercased).
//
#define KEY_RIGHTARROW 0xae
#define KEY_LEFTARROW 0xac
#define KEY_UPARROW 0xad
#define KEY_DOWNARROW 0xaf
#define KEY_ESCAPE 27
#define KEY_ENTER 13
#define KEY_TAB 9
#define KEY_F1 (0x80+0x3b)
#define KEY_F2 (0x80+0x3c)
#define KEY_F3 (0x80+0x3d)
#define KEY_F4 (0x80+0x3e)
#define KEY_F5 (0x80+0x3f)
#define KEY_F6 (0x80+0x40)
#define KEY_F7 (0x80+0x41)
#define KEY_F8 (0x80+0x42)
#define KEY_F9 (0x80+0x43)
#define KEY_F10 (0x80+0x44)
#define KEY_F11 (0x80+0x57)
#define KEY_F12 (0x80+0x58)
#define KEY_BACKSPACE 0x7f
#define KEY_PAUSE 0xff
#define KEY_EQUALS 0x3d
#define KEY_MINUS 0x2d
#define KEY_RSHIFT (0x80+0x36)
#define KEY_RCTRL (0x80+0x1d)
#define KEY_RALT (0x80+0x38)
#define KEY_LALT KEY_RALT
// new keys:
#define KEY_CAPSLOCK (0x80+0x3a)
#define KEY_NUMLOCK (0x80+0x45)
#define KEY_SCRLCK (0x80+0x46)
#define KEY_PRTSCR (0x80+0x59)
#define KEY_HOME (0x80+0x47)
#define KEY_END (0x80+0x4f)
#define KEY_PGUP (0x80+0x49)
#define KEY_PGDN (0x80+0x51)
#define KEY_INS (0x80+0x52)
#define KEY_DEL (0x80+0x53)
#define KEYP_0 KEY_INS
#define KEYP_1 KEY_END
#define KEYP_2 KEY_DOWNARROW
#define KEYP_3 KEY_PGDN
#define KEYP_4 KEY_LEFTARROW
#define KEYP_5 (0x80+0x4c)
#define KEYP_6 KEY_RIGHTARROW
#define KEYP_7 KEY_HOME
#define KEYP_8 KEY_UPARROW
#define KEYP_9 KEY_PGUP
#define KEYP_DIVIDE '/'
#define KEYP_PLUS '+'
#define KEYP_MINUS '-'
#define KEYP_MULTIPLY '*'
#define KEYP_PERIOD 0
#define KEYP_EQUALS KEY_EQUALS
#define KEYP_ENTER KEY_ENTER
#define SCANCODE_TO_KEYS_ARRAY { \
0, 0, 0, 0, 'a', /* 0-9 */ \
'b', 'c', 'd', 'e', 'f', \
'g', 'h', 'i', 'j', 'k', /* 10-19 */ \
'l', 'm', 'n', 'o', 'p', \
'q', 'r', 's', 't', 'u', /* 20-29 */ \
'v', 'w', 'x', 'y', 'z', \
'1', '2', '3', '4', '5', /* 30-39 */ \
'6', '7', '8', '9', '0', \
KEY_ENTER, KEY_ESCAPE, KEY_BACKSPACE, KEY_TAB, ' ', /* 40-49 */ \
KEY_MINUS, KEY_EQUALS, '[', ']', '\\', \
0, ';', '\'', '`', ',', /* 50-59 */ \
'.', '/', KEY_CAPSLOCK, KEY_F1, KEY_F2, \
KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, /* 60-69 */ \
KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, \
KEY_PRTSCR, KEY_SCRLCK, KEY_PAUSE, KEY_INS, KEY_HOME, /* 70-79 */ \
KEY_PGUP, KEY_DEL, KEY_END, KEY_PGDN, KEY_RIGHTARROW, \
KEY_LEFTARROW, KEY_DOWNARROW, KEY_UPARROW, /* 80-89 */ \
KEY_NUMLOCK, KEYP_DIVIDE, \
KEYP_MULTIPLY, KEYP_MINUS, KEYP_PLUS, KEYP_ENTER, KEYP_1, \
KEYP_2, KEYP_3, KEYP_4, KEYP_5, KEYP_6, /* 90-99 */ \
KEYP_7, KEYP_8, KEYP_9, KEYP_0, KEYP_PERIOD, \
0, 0, 0, KEYP_EQUALS, /* 100-103 */ \
}
// Default names for keys, to use in English or as fallback.
#define KEY_NAMES_ARRAY { \
{ KEY_BACKSPACE, "BACKSP" }, { KEY_TAB, "TAB" }, \
{ KEY_INS, "INS" }, { KEY_DEL, "DEL" }, \
{ KEY_PGUP, "PGUP" }, { KEY_PGDN, "PGDN" }, \
{ KEY_ENTER, "ENTER" }, { KEY_ESCAPE, "ESC" }, \
{ KEY_F1, "F1" }, { KEY_F2, "F2" }, \
{ KEY_F3, "F3" }, { KEY_F4, "F4" }, \
{ KEY_F5, "F5" }, { KEY_F6, "F6" }, \
{ KEY_F7, "F7" }, { KEY_F8, "F8" }, \
{ KEY_F9, "F9" }, { KEY_F10, "F10" }, \
{ KEY_F11, "F11" }, { KEY_F12, "F12" }, \
{ KEY_HOME, "HOME" }, { KEY_END, "END" }, \
{ KEY_MINUS, "-" }, { KEY_EQUALS, "=" }, \
{ KEY_NUMLOCK, "NUMLCK" }, { KEY_SCRLCK, "SCRLCK" }, \
{ KEY_PAUSE, "PAUSE" }, { KEY_PRTSCR, "PRTSC" }, \
{ KEY_UPARROW, "UP" }, { KEY_DOWNARROW, "DOWN" }, \
{ KEY_LEFTARROW, "LEFT" }, { KEY_RIGHTARROW, "RIGHT" }, \
{ KEY_RALT, "ALT" }, { KEY_LALT, "ALT" }, \
{ KEY_RSHIFT, "SHIFT" }, { KEY_CAPSLOCK, "CAPS" }, \
{ KEY_RCTRL, "CTRL" }, { KEYP_5, "NUM5" }, \
{ ' ', "SPACE" }, \
{ 'a', "A" }, { 'b', "B" }, { 'c', "C" }, { 'd', "D" }, \
{ 'e', "E" }, { 'f', "F" }, { 'g', "G" }, { 'h', "H" }, \
{ 'i', "I" }, { 'j', "J" }, { 'k', "K" }, { 'l', "L" }, \
{ 'm', "M" }, { 'n', "N" }, { 'o', "O" }, { 'p', "P" }, \
{ 'q', "Q" }, { 'r', "R" }, { 's', "S" }, { 't', "T" }, \
{ 'u', "U" }, { 'v', "V" }, { 'w', "W" }, { 'x', "X" }, \
{ 'y', "Y" }, { 'z', "Z" }, { '0', "0" }, { '1', "1" }, \
{ '2', "2" }, { '3', "3" }, { '4', "4" }, { '5', "5" }, \
{ '6', "6" }, { '7', "7" }, { '8', "8" }, { '9', "9" }, \
{ '[', "[" }, { ']', "]" }, { ';', ";" }, { '`', "`" }, \
{ ',', "," }, { '.', "." }, { '/', "/" }, { '\\', "\\" }, \
{ '\'', "\'" }, \
}
#endif // __DOOMKEYS__
@@ -0,0 +1,8 @@
Makefile.in
Makefile
.deps
guitest
calculator
*.exe
tags
TAGS
@@ -0,0 +1,11 @@
AM_CFLAGS = -I$(top_srcdir)/src -I$(top_srcdir)/textscreen
noinst_PROGRAMS=guitest calculator
guitest_LDADD = ../libtextscreen.a @LDFLAGS@ @SDL_LIBS@
guitest_SOURCES = guitest.c
calculator_LDADD = ../libtextscreen.a @LDFLAGS@ @SDL_LIBS@
calculator_SOURCES = calculator.c
@@ -0,0 +1,180 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Example program: desktop calculator
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "textscreen.h"
typedef enum
{
OP_NONE,
OP_PLUS,
OP_MINUS,
OP_MULT,
OP_DIV,
} operator_t;
int starting_input = 0;
int input_value = 0;
txt_label_t *input_box;
int first_operand;
operator_t operator = OP_NONE;
void UpdateInputBox(void)
{
char buf[20];
TXT_snprintf(buf, sizeof(buf), " %i", input_value);
TXT_SetLabel(input_box, buf);
}
void InsertNumber(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(value))
{
TXT_CAST_ARG(int, value);
if (starting_input)
{
input_value = 0;
starting_input = 0;
}
input_value *= 10;
input_value += *value;
UpdateInputBox();
}
void AddNumberButton(txt_table_t *table, int value)
{
char buf[10];
int *val_copy;
val_copy = malloc(sizeof(int));
*val_copy = value;
TXT_snprintf(buf, sizeof(buf), " %i ", value);
TXT_AddWidget(table, TXT_NewButton2(buf, InsertNumber, val_copy));
}
void Operator(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(op))
{
TXT_CAST_ARG(operator_t, op);
first_operand = input_value;
operator = *op;
starting_input = 1;
}
void AddOperatorButton(txt_table_t *table, const char *label, operator_t op)
{
char buf[10];
operator_t *op_copy;
op_copy = malloc(sizeof(operator_t));
*op_copy = op;
TXT_snprintf(buf, sizeof(buf), " %s ", label);
TXT_AddWidget(table, TXT_NewButton2(buf, Operator, op_copy));
}
void Calculate(TXT_UNCAST_ARG(button), void *unused)
{
switch (operator)
{
case OP_PLUS:
input_value = first_operand + input_value;
break;
case OP_MINUS:
input_value = first_operand - input_value;
break;
case OP_MULT:
input_value = first_operand * input_value;
break;
case OP_DIV:
input_value = first_operand / input_value;
break;
case OP_NONE:
break;
}
UpdateInputBox();
operator = OP_NONE;
starting_input = 1;
}
void BuildGUI()
{
txt_window_t *window;
txt_table_t *table;
window = TXT_NewWindow("Calculator");
input_box = TXT_NewLabel("asdf");
TXT_SetBGColor(input_box, TXT_COLOR_BLACK);
TXT_AddWidget(window, input_box);
TXT_AddWidget(window, TXT_NewSeparator(NULL));
TXT_AddWidget(window, TXT_NewStrut(0, 1));
table = TXT_NewTable(4);
TXT_AddWidget(window, table);
TXT_SetWidgetAlign(table, TXT_HORIZ_CENTER);
AddNumberButton(table, 7);
AddNumberButton(table, 8);
AddNumberButton(table, 9);
AddOperatorButton(table, "*", OP_MULT);
AddNumberButton(table, 4);
AddNumberButton(table, 5);
AddNumberButton(table, 6);
AddOperatorButton(table, "-", OP_MINUS);
AddNumberButton(table, 1);
AddNumberButton(table, 2);
AddNumberButton(table, 3);
AddOperatorButton(table, "+", OP_PLUS);
AddNumberButton(table, 0);
TXT_AddWidget(table, NULL);
TXT_AddWidget(table, TXT_NewButton2(" = ", Calculate, NULL));
AddOperatorButton(table, "/", OP_DIV);
TXT_AddWidget(window, TXT_NewStrut(0, 1));
UpdateInputBox();
}
int main(int argc, char *argv[])
{
if (!TXT_Init())
{
fprintf(stderr, "Failed to initialise GUI\n");
exit(-1);
}
TXT_SetDesktopTitle("Calculator demo");
BuildGUI();
TXT_GUIMainLoop();
TXT_Shutdown();
return 0;
}
@@ -0,0 +1,308 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Example program: GUI test program
//
// Demonstrates all the main textscreen widgets in use and shows how
// a simple textscreen program can be written.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "textscreen.h"
enum
{
RADIO_VALUE_BADGER,
RADIO_VALUE_MUSHROOM,
RADIO_VALUE_SNAKE,
};
// also put some crazy extensions to test the escape function. a"b"c"""dd
const char *extensions[] = { "wad", "lmp", "txt", "a\"b\"c\"\"\"dd", "",
"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"", NULL };
const char *radio_values[] = { "Badger", "Mushroom", "Snake" };
char *textbox_value = NULL;
int numbox_value = 0;
int radiobutton_value;
char *file_path = NULL;
char *dir_path = NULL;
txt_label_t *value_label;
txt_window_t *firstwin;
int cheesy;
void ClosePwnBox(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(window))
{
TXT_CAST_ARG(txt_window_t, window);
TXT_CloseWindow(window);
}
void PwnBox(TXT_UNCAST_ARG(widget), void *user_data)
{
txt_window_t *window;
txt_window_action_t *close_button;
window = TXT_NewWindow("Pwned!");
TXT_AddWidget(window, TXT_NewLabel(" BOOM! HEADSHOT! "));
close_button = TXT_NewWindowAction(KEY_ENTER, "Close");
TXT_SignalConnect(close_button, "pressed", ClosePwnBox, window);
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, close_button);
}
void UpdateLabel(TXT_UNCAST_ARG(widget), void *user_data)
{
char buf[40];
TXT_StringCopy(buf, " Current value: ", sizeof(buf));
if (cheesy)
{
TXT_StringConcat(buf, "Cheesy ", sizeof(buf));
}
TXT_StringConcat(buf, radio_values[radiobutton_value], sizeof(buf));
TXT_StringConcat(buf, "\n", sizeof(buf));
TXT_SetLabel(value_label, buf);
}
void CloseWindow(TXT_UNCAST_ARG(button), void *user_data)
{
TXT_CloseWindow(firstwin);
}
void UnicodeWindow(TXT_UNCAST_ARG(widget), void *user_data)
{
static const char *strings[] = {
"lunedì", "martedì", "mercoledì", "giovedì",
"venerdì", "sabato", "domenica",
};
static int var1, var2;
txt_window_t *window;
window = TXT_NewWindow("Questo è in Italiano");
TXT_AddWidgets(window,
TXT_NewButton("Questo è un tasto"),
TXT_NewCheckBox("Questo è un checkbox", &var1),
TXT_NewDropdownList(&var2, strings, 7),
TXT_NewSeparator("Questo è un separatore"),
TXT_NewLabel("Leggi questo, è pieno di\n"
"informazioni interessanti"),
TXT_NewRadioButton("Ma questo non è un radio??",
&var1, 0),
NULL);
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT,
TXT_NewWindowAction(KEY_ENTER, "Nullità"));
}
void SetupWindow(void)
{
txt_window_t *window;
txt_table_t *table;
txt_table_t *rightpane;
txt_checkbox_t *cheesy_checkbox;
txt_window_action_t *pwn;
txt_label_t *toplabel;
char buf[100];
int i;
window = TXT_NewWindow("Window test");
TXT_SetWindowHelpURL(window, "https://www.youtube.com/watch?v=dQw4w9WgXcQ");
TXT_AddWidget(window, TXT_NewSeparator("Main section"));
table = TXT_NewTable(3);
toplabel = TXT_NewLabel("This is a multiline label.\n"
"A single label object contains \n"
"all three of these lines.");
TXT_AddWidget(window, toplabel);
TXT_SetWidgetAlign(toplabel, TXT_HORIZ_CENTER);
//TXT_AddWidget(window, TXT_NewScrollPane(15, 4, table));
TXT_AddWidget(window, table);
for (i=0; i<3; ++i)
{
TXT_snprintf(buf, sizeof(buf), "Option %i in a table:", i + 1);
TXT_AddWidget(table, TXT_NewLabel(buf));
TXT_snprintf(buf, sizeof(buf), " Button %i-1 ", i + 1);
TXT_AddWidget(table, TXT_NewButton(buf));
TXT_snprintf(buf, sizeof(buf), " Button %i-2 ", i + 1);
TXT_AddWidget(table, TXT_NewButton(buf));
}
TXT_AddWidgets(table,
TXT_NewLabel("Still the same table, but:\n"
"This label magically overflows\n"
"across multiple cells! Cool, huh? "),
TXT_TABLE_OVERFLOW_RIGHT,
TXT_NewButton("Do nothing"),
TXT_TABLE_OVERFLOW_DOWN,
TXT_TABLE_OVERFLOW_DOWN,
TXT_NewButton2("Qualcosa?", UnicodeWindow, NULL),
NULL);
TXT_AddWidget(window, TXT_NewStrut(0, 1));
value_label = TXT_NewLabel("");
TXT_AddWidget(window, value_label);
table = TXT_NewTable(2);
TXT_AddWidget(window, table);
TXT_SetWidgetAlign(table, TXT_HORIZ_CENTER);
cheesy_checkbox = TXT_NewCheckBox("Cheesy", &cheesy);
TXT_AddWidget(table, cheesy_checkbox);
TXT_SignalConnect(cheesy_checkbox, "changed", UpdateLabel, NULL);
rightpane = TXT_NewTable(1);
TXT_AddWidget(table, rightpane);
for (i=0; i<3; ++i)
{
txt_radiobutton_t *rbut;
rbut = TXT_NewRadioButton(radio_values[i], &radiobutton_value, i);
TXT_AddWidget(rightpane, rbut);
TXT_SignalConnect(rbut, "selected", UpdateLabel, NULL);
}
UpdateLabel(NULL, NULL);
TXT_AddWidget(window, TXT_NewButton2("Close Window", CloseWindow, NULL));
pwn = TXT_NewWindowAction(KEY_F1, "PWN!");
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, pwn);
TXT_SignalConnect(pwn, "pressed", PwnBox, NULL);
firstwin = window;
}
void Window2(void)
{
txt_window_t *window;
txt_table_t *table;
txt_table_t *unselectable_table;
txt_scrollpane_t *scrollpane;
window = TXT_NewWindow("Another test");
TXT_SetWindowPosition(window,
TXT_HORIZ_RIGHT,
TXT_VERT_TOP,
TXT_SCREEN_W - 1, 1);
TXT_AddWidgets(window,
TXT_NewScrollPane(40, 1,
TXT_NewLabel("* Unselectable scroll pane *")),
unselectable_table = TXT_NewTable(1),
NULL);
TXT_AddWidget(unselectable_table, TXT_NewLabel("* Unselectable table *"));
TXT_AddWidget(unselectable_table, TXT_NewLabel(
"This is a UTF-8 string:\n"
"\xc3\x80 bient\xc3\xb4t na\xc3\xaet "
"\xc3\xa9v\xc3\xaaque \xc3\xa0 l'\xc5\x93uvre p\xc3\xa8re."));
TXT_AddWidget(window, TXT_NewSeparator("Input boxes"));
table = TXT_NewTable(2);
TXT_AddWidget(window, table);
TXT_AddWidgets(table,
TXT_NewLabel("String: "),
TXT_NewInputBox(&textbox_value, 20),
TXT_NewLabel("Int: "),
TXT_NewIntInputBox(&numbox_value, 10),
TXT_NewLabel("Spin control:"),
TXT_NewSpinControl(&numbox_value, 0, 15),
TXT_NewLabel("File:"),
TXT_NewFileSelector(&file_path, 28, "Select file:",
extensions),
TXT_NewLabel("Directory:"),
TXT_NewFileSelector(&dir_path, 28, "Select directory:",
TXT_DIRECTORY),
NULL);
TXT_AddWidget(window, TXT_NewSeparator("Scroll pane test"));
scrollpane = TXT_NewScrollPane(40, 5, TXT_NewLabel(
"This is a scrollable pane. The contents\n"
"of this box are larger than the box\n"
"itself, but it can be scrolled around\n"
"to explore the full contents.\n"
"\n"
"Scrollable panes can be scrolled both\n"
"vertically and horizontally. They\n"
"can contain any widget. The scroll bars\n"
"appear automatically as needed.\n"
"\n"
"This is a very long line of text that forces a horizontal scrollbar"
));
TXT_AddWidget(window, scrollpane);
}
void ScrollingMenu(void)
{
txt_window_t *window;
txt_button_t *button;
txt_table_t *table;
window = TXT_NewWindow("Scrollable menu");
table = TXT_NewTable(1);
TXT_AddWidgets(table,
TXT_NewButton("Configure display"),
TXT_NewButton("Configure joystick"),
TXT_NewButton("Configure keyboard"),
TXT_NewButton("Configure mouse"),
TXT_NewButton("Configure sound"),
TXT_NewStrut(0, 1),
button = TXT_NewButton("Save Parameters and launch DOOM"),
TXT_NewStrut(0, 1),
TXT_NewButton("Start a network game"),
TXT_NewButton("Join a network game"),
TXT_NewButton("Multiplayer configuration"),
NULL);
TXT_SignalConnect(button, "pressed", PwnBox, NULL);
TXT_AddWidget(window, TXT_NewScrollPane(0, 6, table));
}
int main(int argc, char *argv[])
{
if (!TXT_Init())
{
fprintf(stderr, "Failed to initialise GUI\n");
exit(-1);
}
TXT_SetDesktopTitle("Not Chocolate Doom Setup");
ScrollingMenu();
Window2();
SetupWindow();
TXT_GUIMainLoop();
TXT_Shutdown();
return 0;
}
@@ -0,0 +1,18 @@
FONT_HDRS = small.h normal.h large.h codepage.h
EXTRA_DIST = small.png normal.png large.png convert-font $(FONT_HDRS)
noinst_DATA = $(FONT_HDRS)
if HAVE_FONTS
small.h: small.png convert-font
$(srcdir)/convert-font small small.png small.h
normal.h: normal.png convert-font
$(srcdir)/convert-font normal normal.png normal.h
large.h: large.png convert-font
$(srcdir)/convert-font large large.png large.h
endif
@@ -0,0 +1,38 @@
This directory contains the fonts used by libtextscreen:
* normal.png is the standard DOS font, from the DOSbox project.
Copyright (C) 2002-2004 The DOSBox Team
* small.png contains a miniature, half-size font for low-resolution
displays. This is based on the Atari-Small font by Tom Fine. The
original font was standard ASCII only; this has been extended to the
full Extended ASCII range with scaled-down versions of the full-size
DOS font. Original copyright notice:
Copyright (c) 1999, Thomas A. Fine
License to copy, modify, and distribute for both commercial and
non-commercial use is herby granted, provided this notice
is preserved.
Email to my last name at head.cfa.harvard.edu
http://hea-www.harvard.edu/~fine/
* large.png is a scaled-up version of normal.png with extra detail
added; this is for use on modern high-resolution ("retina") displays.
All modifications and enhancements to the above fonts are:
Copyright (C) 2005-2016 Simon Howard
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
@@ -0,0 +1,113 @@
//
// Copyright(C) 2017 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// This file contains a #define macro mapping from the characters
// in the CP437 code page to the equivalent Unicode characters. It
// therefore defines which Unicode characters can be represented on
// a text screen using such a code page.
//
// If you're changing the textscreen font to show a different code
// page, you should update the mapping in this file to match. The
// Wikipedia pages for DOS code pages are a good place to look for
// this information.
#define CODE_PAGE_TO_UNICODE { \
\
/* CP437 control codes: */ \
\
0x0000, 0x263a, 0x263b, 0x2665, /* 00 - 0f */ \
0x2666, 0x2663, 0x2660, 0x2022, \
0x25d8, 0x25cb, 0x25d9, 0x2642, \
0x2640, 0x266a, 0x266b, 0x263c, \
\
0x25ba, 0x25c4, 0x2195, 0x203c, /* 10 - 1f */ \
0x00b6, 0x00a7, 0x25ac, 0x21a8, \
0x2191, 0x2193, 0x2192, 0x2190, \
0x221f, 0x2194, 0x25b2, 0x25bc, \
\
/* Standard ASCII range: */ \
\
0x0020, 0x0021, 0x0022, 0x0023, /* 20 - 2f */ \
0x0024, 0x0025, 0x0026, 0x0027, \
0x0028, 0x0029, 0x002a, 0x002b, \
0x002c, 0x002d, 0x002e, 0x002f, \
\
0x0030, 0x0031, 0x0032, 0x0033, /* 30 - 3f */ \
0x0034, 0x0035, 0x0036, 0x0037, \
0x0038, 0x0039, 0x003a, 0x003b, \
0x003c, 0x003d, 0x003e, 0x003f, \
\
0x0040, 0x0041, 0x0042, 0x0043, /* 40 - 4f */ \
0x0044, 0x0045, 0x0046, 0x0047, \
0x0048, 0x0049, 0x004a, 0x004b, \
0x004c, 0x004d, 0x004e, 0x004f, \
\
0x0050, 0x0051, 0x0052, 0x0053, /* 50 - 5f */ \
0x0054, 0x0055, 0x0056, 0x0057, \
0x0058, 0x0059, 0x005a, 0x005b, \
0x005c, 0x005d, 0x005e, 0x005f, \
\
0x0060, 0x0061, 0x0062, 0x0063, /* 60 - 6f */ \
0x0064, 0x0065, 0x0066, 0x0067, \
0x0068, 0x0069, 0x006a, 0x006b, \
0x006c, 0x006d, 0x006e, 0x006f, \
\
0x0070, 0x0071, 0x0072, 0x0073, /* 70 - 7f */ \
0x0074, 0x0075, 0x0076, 0x0077, \
0x0078, 0x0079, 0x007a, 0x007b, \
0x007c, 0x007d, 0x007e, 0x2302, \
\
/* CP437 Extended ASCII range: */ \
\
0x00c7, 0x00fc, 0x00e9, 0x00e2, /* 80-8f */ \
0x00e4, 0x00e0, 0x00e5, 0x00e7, \
0x00ea, 0x00eb, 0x00e8, 0x00ef, \
0x00ee, 0x00ec, 0x00c4, 0x00c5, \
\
0x00c9, 0x00e6, 0x00c6, 0x00f4, /* 90-9f */ \
0x00f6, 0x00f2, 0x00fb, 0x00f9, \
0x00ff, 0x00d6, 0x00dc, 0x00a2, \
0x00a3, 0x00a5, 0x20a7, 0x0192, \
\
0x00e1, 0x00ed, 0x00f3, 0x00fa, /* a0-af */ \
0x00f1, 0x00d1, 0x00aa, 0x00ba, \
0x00bf, 0x2310, 0x00ac, 0x00bd, \
0x00bc, 0x00a1, 0x00ab, 0x00bb, \
\
0x2591, 0x2592, 0x2593, 0x2502, /* b0-bf */ \
0x2524, 0x2561, 0x2562, 0x2556, \
0x2555, 0x2563, 0x2551, 0x2557, \
0x255d, 0x255c, 0x255b, 0x2510, \
\
0x2514, 0x2534, 0x252c, 0x251c, /* c0-cf */ \
0x2500, 0x253c, 0x255e, 0x255f, \
0x255a, 0x2554, 0x2569, 0x2566, \
0x2560, 0x2550, 0x256c, 0x2567, \
\
0x2568, 0x2564, 0x2565, 0x2559, /* d0-df */ \
0x2558, 0x2552, 0x2553, 0x256b, \
0x256a, 0x2518, 0x250c, 0x2588, \
0x2584, 0x258c, 0x2590, 0x2580, \
\
0x03b1, 0x00df, 0x0393, 0x03c0, /* e0-ef */ \
0x03a3, 0x03c3, 0x00b5, 0x03c4, \
0x03a6, 0x0398, 0x03a9, 0x03b4, \
0x221e, 0x03c6, 0x03b5, 0x2229, \
\
0x2261, 0x00b1, 0x2265, 0x2264, /* f0-ff */ \
0x2320, 0x2321, 0x00f7, 0x2248, \
0x00b0, 0x2219, 0x00b7, 0x221a, \
0x207f, 0x00b2, 0x25a0, 0x00a0, \
}
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
#
# Copyright(C) 2016 Simon Howard
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# Converts images into libtextscreen fonts.
#
import sys
import os
import re
GRID_COLUMNS = 16
GRID_ROWS = 16
try:
import Image
except ImportError:
try:
from PIL import Image
except ImportError:
print("WARNING: Could not update %s. "
"Please install the Python Imaging library or Pillow."
% sys.argv[3])
sys.exit(0)
def generate_font_data(filename):
"""Read font data from the given file.
Args:
filename: Image file to read.
Returns:
Tuple containing:
(width, height) dimensions of each font character.
Array of byte data for font.
"""
im = Image.open(filename)
width, height = im.size
assert (width % GRID_COLUMNS) == 0
assert (height % GRID_ROWS) == 0
char_w, char_h = width // GRID_COLUMNS, height // GRID_ROWS
font_data_len = (width * height) // 8
font_data = [0] * font_data_len
for y in range(height):
for x in range(width):
px = im.getpixel((x, y))
if px > (127, 127, 127):
char_x, char_y = x // char_w, y // char_h
x1, y1 = x % char_w, y % char_h
bit_index = (
(char_y * GRID_COLUMNS + char_x) * (char_w * char_h) +
(y1 * char_w) + x1)
font_data[bit_index // 8] |= 1 << (bit_index % 8)
return (char_w, char_h), font_data
def convert_image(font_prefix, filename, output_filename):
"""Convert the given image to a text output file.
Args:
font_prefix: Prefix string to attach to constants.
filename: Input image file to read.
output_filename: Header file to write.
"""
dimensions, data = generate_font_data(filename)
with open(output_filename, "w") as outfile:
outfile.write("/* Font data generated from %s; do not edit.\n"
" Please see textscreen/fonts/README for copyright\n"
" information. */\n\n" % filename)
outfile.write("static const uint8_t %s_font_data[] =\n{\n" %
font_prefix)
for index, b in enumerate(data):
if (index % 8) == 0:
outfile.write(" ")
outfile.write("0x%02x," % b)
if ((index + 1) % 8) == 0:
outfile.write("\n")
else:
outfile.write(" ")
outfile.write("};\n")
outfile.write("\n")
outfile.write("static const txt_font_t %s_font =\n{\n" % font_prefix)
outfile.write(" \"%s\", %s_font_data, %d, %d,\n" % (
font_prefix, font_prefix,
dimensions[0], dimensions[1]))
outfile.write("};\n")
convert_image(sys.argv[1], sys.argv[2], sys.argv[3])
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

@@ -0,0 +1,524 @@
/* Font data generated from normal.png; do not edit.
Please see textscreen/fonts/README for copyright
information. */
static const uint8_t normal_font_data[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd,
0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7e, 0xff, 0xdb, 0xff, 0xff, 0xc3,
0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x36, 0x7f, 0x7f, 0x7f,
0x7f, 0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x3e, 0x7f,
0x3e, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0xe7, 0xe7,
0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff,
0x7e, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c,
0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe7, 0xc3,
0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42,
0x42, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd,
0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x78, 0x70, 0x58, 0x4c, 0x1e, 0x33,
0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c,
0x18, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfc, 0xcc, 0xfc, 0x0c, 0x0c, 0x0c,
0x0c, 0x0e, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfe, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6,
0xc6, 0xe6, 0xe7, 0x67, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7,
0x3c, 0xdb, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x7f, 0x1f,
0x0f, 0x07, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x40, 0x60, 0x70, 0x78, 0x7c, 0x7f, 0x7c,
0x78, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18,
0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xfe, 0xdb, 0xdb, 0xdb, 0xde, 0xd8,
0xd8, 0xd8, 0xd8, 0xd8, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3e, 0x63, 0x06, 0x1c, 0x36, 0x63, 0x63,
0x36, 0x1c, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x7f, 0x7f, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18,
0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x7f,
0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x06, 0x7f,
0x06, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03,
0x03, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x66, 0xff,
0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x1c, 0x3e,
0x3e, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x7f, 0x3e, 0x3e,
0x1c, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18,
0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x36, 0x36, 0x7f, 0x36, 0x36,
0x36, 0x7f, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x3e, 0x63, 0x43, 0x03, 0x3e, 0x60,
0x60, 0x61, 0x63, 0x3e, 0x18, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x43, 0x63, 0x30, 0x18,
0x0c, 0x06, 0x63, 0x61, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x36, 0x36, 0x1c, 0x6e, 0x3b,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x0c, 0x0c, 0x06, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x18, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff,
0x3c, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e,
0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x40, 0x60, 0x30, 0x18,
0x0c, 0x06, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x66, 0xc3, 0xc3, 0xdb, 0xdb,
0xc3, 0xc3, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x1c, 0x1e, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x60, 0x30, 0x18, 0x0c,
0x06, 0x03, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x60, 0x60, 0x3c, 0x60,
0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x30, 0x38, 0x3c, 0x36, 0x33, 0x7f,
0x30, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x03, 0x03, 0x03, 0x3f, 0x60,
0x60, 0x60, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x06, 0x03, 0x03, 0x3f, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x63, 0x60, 0x60, 0x30, 0x18,
0x0c, 0x0c, 0x0c, 0x0c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x3e, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x7e, 0x60,
0x60, 0x60, 0x30, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
0x00, 0x18, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06,
0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60,
0x30, 0x18, 0x0c, 0x06, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x30, 0x18, 0x18,
0x18, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x7b, 0x7b,
0x7b, 0x3b, 0x03, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63, 0x7f,
0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x66,
0x66, 0x66, 0x66, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03,
0x03, 0x43, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1f, 0x36, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x36, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16,
0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x66, 0x46, 0x16, 0x1e, 0x16,
0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x7b,
0x63, 0x63, 0x66, 0x5c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x7f, 0x63,
0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x30, 0x30, 0x30, 0x30, 0x30,
0x33, 0x33, 0x33, 0x1e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x67, 0x66, 0x66, 0x36, 0x1e, 0x1e,
0x36, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x46, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xc3,
0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b, 0x73,
0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x06,
0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x6b, 0x7b, 0x3e, 0x30, 0x70, 0x00, 0x00,
0x00, 0x00, 0x3f, 0x66, 0x66, 0x66, 0x3e, 0x36,
0x66, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0x63, 0x63, 0x06, 0x1c, 0x30,
0x60, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3,
0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb,
0xdb, 0xff, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18,
0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xff, 0xc3, 0x61, 0x30, 0x18, 0x0c,
0x06, 0x83, 0xc3, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x03, 0x07, 0x0e, 0x1c,
0x38, 0x70, 0x60, 0x40, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30,
0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x08, 0x1c, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00,
0x0c, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x3e,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x06, 0x06, 0x1e, 0x36, 0x66,
0x66, 0x66, 0x66, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x03,
0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x30, 0x30, 0x3c, 0x36, 0x33,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x7f,
0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06,
0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33,
0x33, 0x33, 0x33, 0x3e, 0x30, 0x33, 0x1e, 0x00,
0x00, 0x00, 0x07, 0x06, 0x06, 0x36, 0x6e, 0x66,
0x66, 0x66, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x1c, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x60, 0x00, 0x70, 0x60, 0x60,
0x60, 0x60, 0x60, 0x60, 0x66, 0x66, 0x3c, 0x00,
0x00, 0x00, 0x07, 0x06, 0x06, 0x66, 0x36, 0x1e,
0x1e, 0x36, 0x66, 0x67, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0xff, 0xdb,
0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x66, 0x66,
0x66, 0x66, 0x66, 0x3e, 0x06, 0x06, 0x0f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x33, 0x33,
0x33, 0x33, 0x33, 0x3e, 0x30, 0x30, 0x78, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x6e, 0x66,
0x06, 0x06, 0x06, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x63, 0x06,
0x1c, 0x30, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x0c, 0x0c, 0x3f, 0x0c, 0x0c,
0x0c, 0x0c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x33, 0x33,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3,
0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c,
0x18, 0x3c, 0x66, 0xc3, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x33, 0x18,
0x0c, 0x06, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0x18, 0x18, 0x18, 0x0e, 0x18,
0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18,
0x18, 0x18, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x1c, 0x36, 0x63,
0x63, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x66, 0x43, 0x03, 0x03, 0x03,
0x43, 0x66, 0x3c, 0x30, 0x60, 0x3e, 0x00, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x33, 0x33, 0x33,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x18, 0x0c, 0x00, 0x3e, 0x63, 0x7f,
0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x36, 0x00, 0x1e, 0x30, 0x3e,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x33, 0x00, 0x00, 0x1e, 0x30, 0x3e,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0c, 0x18, 0x00, 0x1e, 0x30, 0x3e,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x36, 0x1c, 0x00, 0x1e, 0x30, 0x3e,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x06, 0x06,
0x66, 0x3c, 0x30, 0x60, 0x3c, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x7f,
0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x7f,
0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x7f,
0x03, 0x03, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x66, 0x00, 0x00, 0x1c, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x3c, 0x66, 0x00, 0x1c, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0c, 0x18, 0x00, 0x1c, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x63, 0x00, 0x08, 0x1c, 0x36, 0x63, 0x63,
0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x1c, 0x36, 0x1c, 0x00, 0x1c, 0x36, 0x63, 0x63,
0x7f, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x18, 0x0c, 0x06, 0x00, 0x7f, 0x66, 0x06, 0x3e,
0x06, 0x06, 0x66, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0xd8,
0x7e, 0x1b, 0x3b, 0xee, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7c, 0x36, 0x33, 0x33, 0x7f, 0x33,
0x33, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00,
0x00, 0x08, 0x1c, 0x36, 0x00, 0x3e, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x00, 0x00, 0x3e, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0c, 0x18, 0x00, 0x3e, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0c, 0x1e, 0x33, 0x00, 0x33, 0x33, 0x33,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x0c, 0x18, 0x00, 0x33, 0x33, 0x33,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x63, 0x00, 0x00, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x7e, 0x60, 0x30, 0x1e, 0x00,
0x00, 0x63, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x63, 0x00, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x18, 0x7e, 0xc3, 0x03, 0x03, 0x03,
0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x36, 0x26, 0x06, 0x0f, 0x06, 0x06,
0x06, 0x06, 0x67, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18,
0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3f, 0x66, 0x66, 0x3e, 0x46, 0x66, 0xf6,
0x66, 0x66, 0x66, 0xcf, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0xd8, 0x18, 0x18, 0x18, 0x7e, 0x18,
0x18, 0x18, 0x18, 0x18, 0x1b, 0x0e, 0x00, 0x00,
0x00, 0x18, 0x0c, 0x06, 0x00, 0x1e, 0x30, 0x3e,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x30, 0x18, 0x0c, 0x00, 0x1c, 0x18, 0x18,
0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x0c, 0x06, 0x00, 0x3e, 0x63, 0x63,
0x63, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x18, 0x0c, 0x06, 0x00, 0x33, 0x33, 0x33,
0x33, 0x33, 0x33, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x6e, 0x3b, 0x00, 0x3b, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
0x6e, 0x3b, 0x00, 0x63, 0x67, 0x6f, 0x7f, 0x7b,
0x73, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3c, 0x36, 0x36, 0x7c, 0x00, 0x7e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x3e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0c, 0x0c, 0x00, 0x0c, 0x0c, 0x06,
0x03, 0x63, 0x63, 0x3e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x03,
0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60,
0x60, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c,
0x06, 0x73, 0xd9, 0x60, 0x30, 0xf8, 0x00, 0x00,
0x00, 0x03, 0x03, 0x43, 0x63, 0x33, 0x18, 0x0c,
0x66, 0x73, 0x69, 0x7c, 0x60, 0x60, 0x00, 0x00,
0x00, 0x00, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18,
0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x36, 0x1b,
0x36, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x36, 0x6c,
0x36, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22,
0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22,
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55,
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55,
0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee,
0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee, 0xbb, 0xee,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x6f,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x60, 0x6f,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6f, 0x60, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0c, 0xec,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xef,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xec, 0x0c, 0xec,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xef, 0x00, 0xef,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xfc,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0xff,
0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c,
0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b,
0x1b, 0x1b, 0x3b, 0x6e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1e, 0x33, 0x33, 0x33, 0x1b, 0x33,
0x63, 0x63, 0x63, 0x33, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x7f, 0x63, 0x63, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7f, 0x63, 0x06, 0x0c, 0x18,
0x0c, 0x06, 0x63, 0x7f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x1b, 0x1b,
0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66,
0x66, 0x3e, 0x06, 0x06, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66,
0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x7f,
0x63, 0x63, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x36, 0x63, 0x63, 0x63, 0x36,
0x36, 0x36, 0x36, 0x77, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x78, 0x0c, 0x18, 0x30, 0x7c, 0x66,
0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xdb, 0xdb,
0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0x60, 0x7e, 0xdb, 0xdb,
0xcf, 0x7e, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x38, 0x0c, 0x06, 0x06, 0x3e, 0x06,
0x06, 0x06, 0x0c, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x3e, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x7f,
0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18,
0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30,
0x18, 0x0c, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x30, 0x18, 0x0c, 0x06, 0x0c,
0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x70, 0xd8, 0xd8, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x1b, 0x1b, 0x1b, 0x0e, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e,
0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x00,
0x6e, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1c, 0x36, 0x36, 0x1c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x30, 0x37,
0x36, 0x36, 0x3c, 0x38, 0x00, 0x00, 0x00, 0x00,
0x00, 0x1b, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0e, 0x1b, 0x0c, 0x06, 0x13, 0x1f, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x3e, 0x3e, 0x3e, 0x3e,
0x3e, 0x3e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const txt_font_t normal_font =
{
"normal", normal_font_data, 8, 16,
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

@@ -0,0 +1,140 @@
/* Font data generated from small.png; do not edit.
Please see textscreen/fonts/README for copyright
information. */
static const uint8_t small_font_data[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x4e, 0x00,
0xf6, 0xf5, 0xb1, 0x6f, 0x00, 0xea, 0x04, 0x00,
0x00, 0xe4, 0x04, 0x00, 0x40, 0xaa, 0xe4, 0x00,
0x40, 0xee, 0xe4, 0x00, 0x00, 0x60, 0x06, 0x00,
0xff, 0x9f, 0xf9, 0xff, 0x00, 0x96, 0x69, 0x00,
0xff, 0x69, 0x96, 0xff, 0xe0, 0x74, 0x75, 0x00,
0x60, 0x69, 0x6f, 0x06, 0xc0, 0x44, 0x74, 0x03,
0xe0, 0xaa, 0xba, 0x03, 0x22, 0x27, 0x27, 0x22,
0x10, 0x73, 0x13, 0x00, 0x80, 0xec, 0x8c, 0x00,
0x40, 0x4e, 0xe4, 0x04, 0xa0, 0xaa, 0xa0, 0x00,
0xf0, 0xb9, 0xaa, 0x00, 0x16, 0x96, 0x86, 0x06,
0x00, 0x00, 0xff, 0x00, 0x40, 0x4e, 0xe4, 0xf4,
0x40, 0x4e, 0x44, 0x04, 0x40, 0x44, 0xe4, 0x04,
0x20, 0xf4, 0x24, 0x00, 0x40, 0xf2, 0x42, 0x00,
0x00, 0x10, 0x07, 0x00, 0x00, 0xf5, 0x05, 0x00,
0x00, 0x72, 0x0f, 0x00, 0x00, 0x7f, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x22, 0x02, 0x02,
0x50, 0x05, 0x00, 0x00, 0x50, 0x57, 0x75, 0x05,
0x22, 0x25, 0x54, 0x22, 0x50, 0x24, 0x12, 0x05,
0x52, 0x52, 0x35, 0x06, 0x20, 0x02, 0x00, 0x00,
0x40, 0x22, 0x22, 0x04, 0x10, 0x22, 0x22, 0x01,
0x50, 0x72, 0x52, 0x00, 0x20, 0x72, 0x22, 0x00,
0x00, 0x00, 0x20, 0x12, 0x00, 0x70, 0x00, 0x00,
0x00, 0x00, 0x20, 0x02, 0x40, 0x24, 0x12, 0x01,
0x20, 0x75, 0x55, 0x02, 0x20, 0x23, 0x22, 0x07,
0x20, 0x45, 0x12, 0x07, 0x70, 0x24, 0x54, 0x02,
0x40, 0x56, 0x47, 0x04, 0x70, 0x31, 0x54, 0x02,
0x60, 0x31, 0x55, 0x02, 0x70, 0x44, 0x22, 0x02,
0x20, 0x25, 0x55, 0x02, 0x20, 0x55, 0x46, 0x03,
0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x01,
0x00, 0x24, 0x21, 0x04, 0x00, 0x07, 0x07, 0x00,
0x00, 0x21, 0x24, 0x01, 0x20, 0x45, 0x02, 0x02,
0x20, 0x55, 0x11, 0x06, 0x20, 0x55, 0x57, 0x05,
0x30, 0x35, 0x55, 0x03, 0x20, 0x15, 0x51, 0x02,
0x30, 0x55, 0x55, 0x03, 0x70, 0x71, 0x11, 0x07,
0x70, 0x71, 0x11, 0x01, 0x20, 0x15, 0x55, 0x02,
0x50, 0x75, 0x55, 0x05, 0x70, 0x22, 0x22, 0x07,
0x40, 0x44, 0x54, 0x02, 0x50, 0x35, 0x55, 0x05,
0x10, 0x11, 0x11, 0x07, 0x50, 0x57, 0x55, 0x05,
0x40, 0x75, 0x57, 0x01, 0x20, 0x55, 0x55, 0x02,
0x30, 0x55, 0x13, 0x01, 0x20, 0x55, 0x35, 0x06,
0x30, 0x55, 0x53, 0x05, 0x20, 0x25, 0x54, 0x02,
0x70, 0x22, 0x22, 0x02, 0x50, 0x55, 0x55, 0x07,
0x50, 0x55, 0x55, 0x02, 0x50, 0x55, 0x75, 0x05,
0x50, 0x25, 0x55, 0x05, 0x50, 0x25, 0x22, 0x02,
0x70, 0x24, 0x12, 0x07, 0x60, 0x22, 0x22, 0x06,
0x10, 0x21, 0x42, 0x04, 0x30, 0x22, 0x22, 0x03,
0x20, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x10, 0x02, 0x00, 0x00, 0x00, 0x43, 0x56, 0x06,
0x10, 0x31, 0x55, 0x03, 0x00, 0x16, 0x11, 0x06,
0x40, 0x64, 0x55, 0x06, 0x00, 0x52, 0x17, 0x06,
0x40, 0x72, 0x22, 0x02, 0x00, 0x56, 0x65, 0x34,
0x10, 0x31, 0x55, 0x05, 0x20, 0x30, 0x22, 0x07,
0x40, 0x60, 0x44, 0x34, 0x10, 0x51, 0x53, 0x05,
0x20, 0x22, 0x22, 0x02, 0x00, 0x75, 0x55, 0x05,
0x00, 0x53, 0x55, 0x05, 0x00, 0x52, 0x55, 0x02,
0x00, 0x53, 0x35, 0x11, 0x00, 0x56, 0x65, 0x44,
0x00, 0x16, 0x11, 0x01, 0x00, 0x16, 0x42, 0x03,
0x20, 0x72, 0x22, 0x02, 0x00, 0x55, 0x55, 0x07,
0x00, 0x55, 0x55, 0x02, 0x00, 0x55, 0x75, 0x05,
0x00, 0x55, 0x52, 0x05, 0x00, 0x55, 0x65, 0x34,
0x00, 0x47, 0x12, 0x07, 0x24, 0x12, 0x22, 0x04,
0x22, 0x02, 0x22, 0x02, 0x21, 0x42, 0x22, 0x01,
0xa0, 0x05, 0x00, 0x00, 0x20, 0x55, 0x75, 0x00,
0x20, 0x15, 0x51, 0x32, 0x05, 0x55, 0x55, 0x07,
0x12, 0x52, 0x17, 0x06, 0xa4, 0x43, 0x56, 0x06,
0x05, 0x43, 0x56, 0x06, 0x42, 0x43, 0x56, 0x06,
0x52, 0x42, 0x56, 0x06, 0x00, 0x16, 0x11, 0x36,
0x52, 0x52, 0x17, 0x06, 0x05, 0x52, 0x17, 0x06,
0x42, 0x52, 0x17, 0x06, 0x50, 0x30, 0x22, 0x07,
0x52, 0x30, 0x22, 0x07, 0x42, 0x30, 0x22, 0x07,
0x05, 0x52, 0x57, 0x05, 0x52, 0x52, 0x57, 0x05,
0x24, 0x17, 0x13, 0x07, 0x00, 0xad, 0x5e, 0x0e,
0xe0, 0xf5, 0x55, 0x0d, 0x52, 0x20, 0x55, 0x02,
0x05, 0x52, 0x55, 0x02, 0x42, 0x52, 0x55, 0x02,
0x52, 0x50, 0x55, 0x07, 0x42, 0x50, 0x55, 0x07,
0x05, 0x55, 0x65, 0x34, 0x05, 0x52, 0x55, 0x02,
0x05, 0x55, 0x55, 0x07, 0x20, 0x16, 0x61, 0x02,
0x2c, 0x72, 0x22, 0x0f, 0x50, 0x25, 0x27, 0x02,
0x30, 0x35, 0xd5, 0x05, 0x48, 0xe4, 0x54, 0x02,
0x24, 0x43, 0x56, 0x06, 0x24, 0x30, 0x22, 0x07,
0x12, 0x52, 0x55, 0x02, 0x24, 0x50, 0x55, 0x07,
0x5a, 0x30, 0x55, 0x05, 0x5a, 0x90, 0xdb, 0x09,
0x56, 0x0e, 0x0f, 0x00, 0x52, 0x02, 0x07, 0x00,
0x20, 0x20, 0x51, 0x02, 0x00, 0x70, 0x11, 0x00,
0x00, 0xe0, 0x88, 0x00, 0x11, 0x25, 0x8d, 0xc4,
0x11, 0x25, 0xa1, 0x8e, 0x20, 0x20, 0x22, 0x02,
0x00, 0xa0, 0xa5, 0x00, 0x00, 0x50, 0x5a, 0x00,
0x28, 0x28, 0x28, 0x28, 0x5a, 0x5a, 0x5a, 0x5a,
0xeb, 0xeb, 0xeb, 0xeb, 0x44, 0x44, 0x44, 0x44,
0x44, 0x74, 0x44, 0x44, 0x44, 0x47, 0x47, 0x44,
0xaa, 0xba, 0xaa, 0xaa, 0x00, 0xf0, 0xaa, 0xaa,
0x00, 0x47, 0x47, 0x44, 0xaa, 0x8b, 0xab, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x8f, 0xab, 0xaa,
0xaa, 0x8b, 0x0f, 0x00, 0xaa, 0xfa, 0x00, 0x00,
0x44, 0x47, 0x07, 0x00, 0x00, 0x70, 0x44, 0x44,
0x44, 0xc4, 0x00, 0x00, 0x44, 0xf4, 0x00, 0x00,
0x00, 0xf0, 0x44, 0x44, 0x44, 0xc4, 0x44, 0x44,
0x00, 0xf0, 0x00, 0x00, 0x44, 0xf4, 0x44, 0x44,
0x44, 0x4c, 0x4c, 0x44, 0xaa, 0xaa, 0xaa, 0xaa,
0xaa, 0x2a, 0x0e, 0x00, 0x00, 0x2e, 0xaa, 0xaa,
0xaa, 0x0b, 0x0f, 0x00, 0x00, 0x0f, 0xab, 0xaa,
0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x0f, 0x0f, 0x00,
0xaa, 0x0b, 0xab, 0xaa, 0x44, 0x0f, 0x0f, 0x00,
0xaa, 0xfa, 0x00, 0x00, 0x00, 0x0f, 0x4f, 0x44,
0x00, 0xf0, 0xaa, 0xaa, 0xaa, 0xea, 0x00, 0x00,
0x44, 0x4c, 0x0c, 0x00, 0x00, 0x4c, 0x4c, 0x44,
0x00, 0xe0, 0xaa, 0xaa, 0xaa, 0xfa, 0xaa, 0xaa,
0x44, 0x4f, 0x4f, 0x44, 0x44, 0x74, 0x00, 0x00,
0x00, 0xc0, 0x44, 0x44, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0xff, 0xff, 0x33, 0x33, 0x33, 0x33,
0xcc, 0xcc, 0xcc, 0xcc, 0xff, 0xff, 0x00, 0x00,
0x00, 0xa0, 0x55, 0x0a, 0x30, 0x35, 0x95, 0x05,
0xf0, 0x19, 0x11, 0x01, 0x00, 0x5f, 0x55, 0x05,
0x00, 0x17, 0x12, 0x07, 0x00, 0x5e, 0x55, 0x02,
0x00, 0xaa, 0x2e, 0x01, 0x00, 0x5a, 0x44, 0x04,
0x70, 0x52, 0x25, 0x07, 0x20, 0x75, 0x55, 0x02,
0x60, 0x99, 0x66, 0x0f, 0x60, 0x21, 0x55, 0x02,
0x00, 0xd6, 0x6b, 0x00, 0x80, 0x9f, 0xf9, 0x01,
0x60, 0x71, 0x11, 0x06, 0x20, 0x55, 0x55, 0x05,
0x70, 0x70, 0x70, 0x00, 0x20, 0x27, 0x70, 0x00,
0x10, 0x42, 0x12, 0x07, 0x40, 0x12, 0x42, 0x07,
0x80, 0x44, 0x44, 0x44, 0x44, 0x44, 0x25, 0x00,
0x00, 0x02, 0x07, 0x02, 0xa0, 0x05, 0x5a, 0x00,
0x52, 0x02, 0x00, 0x00, 0x00, 0x60, 0x06, 0x00,
0x00, 0x00, 0x02, 0x00, 0x4c, 0x54, 0x46, 0x00,
0x57, 0x55, 0x00, 0x00, 0x43, 0x72, 0x00, 0x00,
0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const txt_font_t small_font =
{
"small", small_font_data, 4, 8,
};
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,48 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TEXTSCREEN_H
#define TEXTSCREEN_H
#ifdef __cplusplus
extern "C" {
#endif
#include "../include/doomkeys.h"
#include "txt_main.h"
#include "txt_button.h"
#include "txt_checkbox.h"
#include "txt_conditional.h"
#include "txt_desktop.h"
#include "txt_dropdown.h"
#include "txt_fileselect.h"
#include "txt_inputbox.h"
#include "txt_label.h"
#include "txt_radiobutton.h"
#include "txt_scrollpane.h"
#include "txt_separator.h"
#include "txt_spinctrl.h"
#include "txt_strut.h"
#include "txt_table.h"
#include "txt_widget.h"
#include "txt_window_action.h"
#include "txt_window.h"
#ifdef __cplusplus
}
#endif
#endif /* #ifndef TEXTSCREEN_H */
@@ -0,0 +1,131 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_button.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
static void TXT_ButtonSizeCalc(TXT_UNCAST_ARG(button))
{
TXT_CAST_ARG(txt_button_t, button);
button->widget.w = TXT_UTF8_Strlen(button->label);
button->widget.h = 1;
}
static void TXT_ButtonDrawer(TXT_UNCAST_ARG(button))
{
TXT_CAST_ARG(txt_button_t, button);
int i;
int w;
w = button->widget.w;
TXT_SetWidgetBG(button);
TXT_DrawString(button->label);
for (i = TXT_UTF8_Strlen(button->label); i < w; ++i)
{
TXT_DrawString(" ");
}
}
static void TXT_ButtonDestructor(TXT_UNCAST_ARG(button))
{
TXT_CAST_ARG(txt_button_t, button);
free(button->label);
}
static int TXT_ButtonKeyPress(TXT_UNCAST_ARG(button), int key)
{
TXT_CAST_ARG(txt_button_t, button);
if (key == KEY_ENTER)
{
TXT_EmitSignal(button, "pressed");
return 1;
}
return 0;
}
static void TXT_ButtonMousePress(TXT_UNCAST_ARG(button), int x, int y, int b)
{
TXT_CAST_ARG(txt_button_t, button);
if (b == TXT_MOUSE_LEFT)
{
// Equivalent to pressing enter
TXT_ButtonKeyPress(button, KEY_ENTER);
}
}
txt_widget_class_t txt_button_class =
{
TXT_AlwaysSelectable,
TXT_ButtonSizeCalc,
TXT_ButtonDrawer,
TXT_ButtonKeyPress,
TXT_ButtonDestructor,
TXT_ButtonMousePress,
NULL,
};
void TXT_SetButtonLabel(txt_button_t *button, const char *label)
{
free(button->label);
button->label = strdup(label);
}
txt_button_t *TXT_NewButton(const char *label)
{
txt_button_t *button;
button = malloc(sizeof(txt_button_t));
TXT_InitWidget(button, &txt_button_class);
button->label = strdup(label);
return button;
}
// Button with a callback set automatically
txt_button_t *TXT_NewButton2(const char *label, TxtWidgetSignalFunc func,
void *user_data)
{
txt_button_t *button;
button = TXT_NewButton(label);
TXT_SignalConnect(button, "pressed", func, user_data);
return button;
}
@@ -0,0 +1,74 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_BUTTON_H
#define TXT_BUTTON_H
/**
* @file txt_button.h
*
* Button widget.
*/
/**
* Button widget.
*
* A button is a widget that can be selected to perform some action.
* When a button is pressed, it emits the "pressed" signal.
*/
typedef struct txt_button_s txt_button_t;
#include "txt_widget.h"
struct txt_button_s
{
txt_widget_t widget;
char *label;
};
/**
* Create a new button widget.
*
* @param label The label to use on the new button (UTF-8 format).
* @return Pointer to the new button widget.
*/
txt_button_t *TXT_NewButton(const char *label);
/**
* Create a new button widget, binding the "pressed" signal to a
* specified callback function.
*
* @param label The label to use on the new button (UTF-8 format).
* @param func The callback function to invoke.
* @param user_data User-specified pointer to pass to the callback.
* @return Pointer to the new button widget.
*/
txt_button_t *TXT_NewButton2(const char *label, TxtWidgetSignalFunc func,
void *user_data);
/**
* Change the label used on a button.
*
* @param button The button.
* @param label The new label (UTF-8 format).
*/
void TXT_SetButtonLabel(txt_button_t *button, const char *label);
#endif /* #ifndef TXT_BUTTON_H */
@@ -0,0 +1,146 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_checkbox.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
static void TXT_CheckBoxSizeCalc(TXT_UNCAST_ARG(checkbox))
{
TXT_CAST_ARG(txt_checkbox_t, checkbox);
// Minimum width is the string length + right-side space for padding
checkbox->widget.w = TXT_UTF8_Strlen(checkbox->label) + 5;
checkbox->widget.h = 1;
}
static void TXT_CheckBoxDrawer(TXT_UNCAST_ARG(checkbox))
{
TXT_CAST_ARG(txt_checkbox_t, checkbox);
txt_saved_colors_t colors;
int i;
int w;
w = checkbox->widget.w;
TXT_SaveColors(&colors);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString("(");
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
if ((*checkbox->variable != 0) ^ checkbox->inverted)
{
TXT_DrawCodePageString("\x07");
}
else
{
TXT_DrawString(" ");
}
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString(") ");
TXT_RestoreColors(&colors);
TXT_SetWidgetBG(checkbox);
TXT_DrawString(checkbox->label);
for (i = TXT_UTF8_Strlen(checkbox->label); i < w-4; ++i)
{
TXT_DrawString(" ");
}
}
static void TXT_CheckBoxDestructor(TXT_UNCAST_ARG(checkbox))
{
TXT_CAST_ARG(txt_checkbox_t, checkbox);
free(checkbox->label);
}
static int TXT_CheckBoxKeyPress(TXT_UNCAST_ARG(checkbox), int key)
{
TXT_CAST_ARG(txt_checkbox_t, checkbox);
if (key == KEY_ENTER || key == ' ')
{
*checkbox->variable = !*checkbox->variable;
TXT_EmitSignal(checkbox, "changed");
return 1;
}
return 0;
}
static void TXT_CheckBoxMousePress(TXT_UNCAST_ARG(checkbox), int x, int y, int b)
{
TXT_CAST_ARG(txt_checkbox_t, checkbox);
if (b == TXT_MOUSE_LEFT)
{
// Equivalent to pressing enter
TXT_CheckBoxKeyPress(checkbox, KEY_ENTER);
}
}
txt_widget_class_t txt_checkbox_class =
{
TXT_AlwaysSelectable,
TXT_CheckBoxSizeCalc,
TXT_CheckBoxDrawer,
TXT_CheckBoxKeyPress,
TXT_CheckBoxDestructor,
TXT_CheckBoxMousePress,
NULL,
};
txt_checkbox_t *TXT_NewCheckBox(const char *label, int *variable)
{
txt_checkbox_t *checkbox;
checkbox = malloc(sizeof(txt_checkbox_t));
TXT_InitWidget(checkbox, &txt_checkbox_class);
checkbox->label = strdup(label);
checkbox->variable = variable;
checkbox->inverted = 0;
return checkbox;
}
txt_checkbox_t *TXT_NewInvertedCheckBox(const char *label, int *variable)
{
txt_checkbox_t *result;
result = TXT_NewCheckBox(label, variable);
result->inverted = 1;
return result;
}
@@ -0,0 +1,76 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_CHECKBOX_H
#define TXT_CHECKBOX_H
/**
* @file txt_checkbox.h
*
* Checkbox widget.
*/
/**
* Checkbox widget.
*
* A checkbox is used to control boolean values that may be either on
* or off. The widget has a label that is displayed to the right of
* the checkbox indicator. The widget tracks an integer variable;
* if the variable is non-zero, the checkbox is checked, while if it
* is zero, the checkbox is unchecked. It is also possible to
* create "inverted" checkboxes where this logic is reversed.
*
* When a checkbox is changed, it emits the "changed" signal.
*/
typedef struct txt_checkbox_s txt_checkbox_t;
#include "txt_widget.h"
struct txt_checkbox_s
{
txt_widget_t widget;
char *label;
int *variable;
int inverted;
};
/**
* Create a new checkbox.
*
* @param label The label for the new checkbox (UTF-8 format).
* @param variable Pointer to the variable containing this checkbox's
* value.
* @return Pointer to the new checkbox.
*/
txt_checkbox_t *TXT_NewCheckBox(const char *label, int *variable);
/**
* Create a new inverted checkbox.
*
* An inverted checkbox displays the opposite of a normal checkbox;
* where it would be checked, it appears unchecked, and vice-versa.
*
* @param label The label for the new checkbox (UTF-8 format).
* @param variable Pointer to the variable containing this checkbox's
* value.
* @return Pointer to the new checkbox.
*/
txt_checkbox_t *TXT_NewInvertedCheckBox(const char *label, int *variable);
#endif /* #ifndef TXT_CHECKBOX_H */
@@ -0,0 +1,168 @@
//
// Copyright(C) 2016 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "txt_conditional.h"
#include "txt_strut.h"
struct txt_conditional_s
{
txt_widget_t widget;
int *var;
int expected_value;
txt_widget_t *child;
};
static int ConditionTrue(txt_conditional_t *conditional)
{
return *conditional->var == conditional->expected_value;
}
static int TXT_CondSelectable(TXT_UNCAST_ARG(conditional))
{
TXT_CAST_ARG(txt_conditional_t, conditional);
return ConditionTrue(conditional)
&& TXT_SelectableWidget(conditional->child);
}
static void TXT_CondSizeCalc(TXT_UNCAST_ARG(conditional))
{
TXT_CAST_ARG(txt_conditional_t, conditional);
if (!ConditionTrue(conditional))
{
conditional->widget.w = 0;
conditional->widget.h = 0;
}
else
{
TXT_CalcWidgetSize(conditional->child);
conditional->widget.w = conditional->child->w;
conditional->widget.h = conditional->child->h;
}
}
static void TXT_CondLayout(TXT_UNCAST_ARG(conditional))
{
TXT_CAST_ARG(txt_conditional_t, conditional);
if (ConditionTrue(conditional))
{
conditional->child->x = conditional->widget.x;
conditional->child->y = conditional->widget.y;
TXT_LayoutWidget(conditional->child);
}
}
static void TXT_CondDrawer(TXT_UNCAST_ARG(conditional))
{
TXT_CAST_ARG(txt_conditional_t, conditional);
if (ConditionTrue(conditional))
{
TXT_DrawWidget(conditional->child);
}
}
static void TXT_CondDestructor(TXT_UNCAST_ARG(conditional))
{
TXT_CAST_ARG(txt_conditional_t, conditional);
TXT_DestroyWidget(conditional->child);
}
static void TXT_CondFocused(TXT_UNCAST_ARG(conditional), int focused)
{
TXT_CAST_ARG(txt_conditional_t, conditional);
if (ConditionTrue(conditional))
{
TXT_SetWidgetFocus(conditional->child, focused);
}
}
static int TXT_CondKeyPress(TXT_UNCAST_ARG(conditional), int key)
{
TXT_CAST_ARG(txt_conditional_t, conditional);
if (ConditionTrue(conditional))
{
return TXT_WidgetKeyPress(conditional->child, key);
}
return 0;
}
static void TXT_CondMousePress(TXT_UNCAST_ARG(conditional),
int x, int y, int b)
{
TXT_CAST_ARG(txt_conditional_t, conditional);
if (ConditionTrue(conditional))
{
TXT_WidgetMousePress(conditional->child, x, y, b);
}
}
txt_widget_class_t txt_conditional_class =
{
TXT_CondSelectable,
TXT_CondSizeCalc,
TXT_CondDrawer,
TXT_CondKeyPress,
TXT_CondDestructor,
TXT_CondMousePress,
TXT_CondLayout,
TXT_CondFocused,
};
txt_conditional_t *TXT_NewConditional(int *var, int expected_value,
TXT_UNCAST_ARG(child))
{
TXT_CAST_ARG(txt_widget_t, child);
txt_conditional_t *conditional;
conditional = malloc(sizeof(txt_conditional_t));
TXT_InitWidget(conditional, &txt_conditional_class);
conditional->var = var;
conditional->expected_value = expected_value;
conditional->child = child;
child->parent = &conditional->widget;
return conditional;
}
// "Static" conditional that returns an empty strut if the given static
// value is false. Kind of like a conditional but we only evaluate it at
// creation time.
txt_widget_t *TXT_If(int conditional, TXT_UNCAST_ARG(child))
{
TXT_CAST_ARG(txt_widget_t, child);
if (conditional)
{
return child;
}
else
{
txt_strut_t *nullwidget;
TXT_DestroyWidget(child);
nullwidget = TXT_NewStrut(0, 0);
return &nullwidget->widget;
}
}
@@ -0,0 +1,63 @@
//
// Copyright(C) 2016 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_CONDITIONAL_H
#define TXT_CONDITIONAL_H
/**
* @file txt_conditional.h
*
* Conditional widget.
*/
/**
* Conditional widget.
*
* A conditional widget contains another widget, and conditionally
* shows or hides it based on the value of a variable.
*/
typedef struct txt_conditional_s txt_conditional_t;
#include "txt_widget.h"
/**
* Create a new conditional widget.
*
* @param var The variable to check.
* @param expected_value If the variable has this value, the widget is shown.
* @param child The inner widget to show or hide.
* @return Pointer to the new conditional widget.
*/
txt_conditional_t *TXT_NewConditional(int *var, int expected_value,
TXT_UNCAST_ARG(child));
/**
* Return the given child widget if the given boolean condition is true.
*
* If the condition is not true, the child widget is destroyed and a dummy
* "null" widget is returned that shows nothing.
*
* @param condition Boolean condition - true or false value.
* @param child Widget to conditionally return.
* @return Either child (if condition is true) or a null
* widget.
*/
txt_widget_t *TXT_If(int condition, TXT_UNCAST_ARG(child));
#endif /* #ifndef TXT_CONDITIONAL_H */
@@ -0,0 +1,413 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_desktop.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_separator.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
#define HELP_KEY KEY_F1
#define MAXWINDOWS 128
static char *desktop_title;
static txt_window_t *all_windows[MAXWINDOWS];
static int num_windows = 0;
static int main_loop_running = 0;
static TxtIdleCallback periodic_callback = NULL;
static void *periodic_callback_data;
static unsigned int periodic_callback_period;
static char *help_label;
void TXT_AddDesktopWindow(txt_window_t *win)
{
// Previously-top window loses focus:
if (num_windows > 0)
{
TXT_SetWindowFocus(all_windows[num_windows - 1], 0);
}
all_windows[num_windows] = win;
++num_windows;
// New window gains focus:
TXT_SetWindowFocus(win, 1);
}
void TXT_RemoveDesktopWindow(txt_window_t *win)
{
int from, to;
// Window must lose focus if it's being removed:
TXT_SetWindowFocus(win, 0);
for (from=0, to=0; from<num_windows; ++from)
{
if (all_windows[from] != win)
{
all_windows[to] = all_windows[from];
++to;
}
}
num_windows = to;
// Top window gains focus:
if (num_windows > 0)
{
TXT_SetWindowFocus(all_windows[num_windows - 1], 1);
}
}
txt_window_t *TXT_GetActiveWindow(void)
{
if (num_windows == 0)
{
return NULL;
}
return all_windows[num_windows - 1];
}
int TXT_RaiseWindow(txt_window_t *window)
{
int i;
for (i = 0; i < num_windows - 1; ++i)
{
if (all_windows[i] == window)
{
all_windows[i] = all_windows[i + 1];
all_windows[i + 1] = window;
if (i == num_windows - 2)
{
TXT_SetWindowFocus(all_windows[i], 0);
TXT_SetWindowFocus(window, 1);
}
return 1;
}
}
// Window not in the list, or at the end of the list (top) already.
return 0;
}
int TXT_LowerWindow(txt_window_t *window)
{
int i;
for (i = 0; i < num_windows - 1; ++i)
{
if (all_windows[i + 1] == window)
{
all_windows[i + 1] = all_windows[i];
all_windows[i] = window;
if (i == num_windows - 2)
{
TXT_SetWindowFocus(window, 0);
TXT_SetWindowFocus(all_windows[i + 1], 1);
}
return 1;
}
}
// Window not in the list, or at the start of the list (bottom) already.
return 0;
}
static void DrawDesktopBackground(const char *title, const char* title_help)
{
int i;
unsigned char *screendata;
unsigned char *p;
screendata = TXT_GetScreenData();
// Fill the screen with gradient characters
p = screendata;
for (i=0; i<TXT_SCREEN_W * TXT_SCREEN_H; ++i)
{
*p++ = 0xb1;
*p++ = TXT_COLOR_GREY | (TXT_COLOR_BLUE << 4);
}
// Draw the top and bottom banners
p = screendata;
for (i = 0; i<TXT_SCREEN_W; ++i)
{
*p++ = ' ';
*p++ = TXT_COLOR_BLACK | (TXT_COLOR_GREY << 4);
}
p = screendata + (TXT_SCREEN_H - 1) * TXT_SCREEN_W * 2;
for (i = 0; i<TXT_SCREEN_W; ++i)
{
*p++ = ' ';
*p++ = TXT_COLOR_BLACK | (TXT_COLOR_GREY << 4);
}
// Print the title
TXT_GotoXY(0, 0);
TXT_FGColor(TXT_COLOR_BLACK);
TXT_BGColor(TXT_COLOR_GREY, 0);
TXT_PutChar(' ');
TXT_Puts(title);
// Help Text on bottom banner
TXT_GotoXY(0, 24);
TXT_FGColor(TXT_COLOR_DARK_GREY);
TXT_BGColor(TXT_COLOR_GREY, 0);
TXT_DrawString(" ");
TXT_DrawString(title_help);
}
static void DrawHelpIndicator(void)
{
char keybuf[10];
int fgcolor;
int x, y;
TXT_GetKeyDescription(HELP_KEY, keybuf, sizeof(keybuf));
TXT_GetMousePosition(&x, &y);
if (y == 0 && x >= TXT_SCREEN_W - 9)
{
fgcolor = TXT_COLOR_GREY;
TXT_BGColor(TXT_COLOR_BLACK, 0);
}
else
{
fgcolor = TXT_COLOR_BLACK;
TXT_BGColor(TXT_COLOR_GREY, 0);
}
TXT_GotoXY(TXT_SCREEN_W - 9, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
TXT_DrawString(" ");
TXT_DrawString(keybuf);
TXT_FGColor(fgcolor);
TXT_DrawString("=Help ");
}
void TXT_DrawHelpLabel(const char* title)
{
free(help_label);
help_label = strdup(title);
}
void TXT_SetDesktopTitle(const char *title)
{
free(desktop_title);
desktop_title = strdup(title);
TXT_SetWindowTitle(title);
}
void TXT_DrawDesktop(void)
{
txt_window_t *active_window;
const char *title;
const char* title_help;
int i;
TXT_InitClipArea();
if (desktop_title == NULL)
title = "";
else
title = desktop_title;
if (help_label == NULL)
title_help = "";
else
title_help = help_label;
DrawDesktopBackground(title, title_help);
active_window = TXT_GetActiveWindow();
if (active_window != NULL && active_window->help_url != NULL)
{
DrawHelpIndicator();
}
for (i=0; i<num_windows; ++i)
{
TXT_DrawWindow(all_windows[i]);
}
TXT_UpdateScreen();
}
// Fallback function to handle key/mouse events that are not handled by
// the active window.
static void DesktopInputEvent(int c)
{
txt_window_t *active_window;
int x, y;
switch (c)
{
case TXT_MOUSE_LEFT:
TXT_GetMousePosition(&x, &y);
// Clicking the top-right of the screen is equivalent
// to pressing the help key.
if (y == 0 && x >= TXT_SCREEN_W - 9)
{
DesktopInputEvent(HELP_KEY);
}
break;
case HELP_KEY:
active_window = TXT_GetActiveWindow();
if (active_window != NULL)
{
TXT_OpenWindowHelpURL(active_window);
}
break;
default:
break;
}
}
void TXT_DispatchEvents(void)
{
txt_window_t *active_window;
int c;
while ((c = TXT_GetChar()) > 0)
{
active_window = TXT_GetActiveWindow();
if (active_window != NULL && !TXT_WindowKeyPress(active_window, c))
{
DesktopInputEvent(c);
}
}
}
void TXT_ExitMainLoop(void)
{
main_loop_running = 0;
}
void TXT_DrawASCIITable(void)
{
unsigned char *screendata;
char buf[10];
int x, y;
int n;
screendata = TXT_GetScreenData();
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
TXT_BGColor(TXT_COLOR_BLACK, 0);
for (y=0; y<16; ++y)
{
for (x=0; x<16; ++x)
{
n = y * 16 + x;
TXT_GotoXY(x * 5, y);
TXT_snprintf(buf, sizeof(buf), "%02x ", n);
TXT_Puts(buf);
// Write the character directly to the screen memory buffer:
screendata[(y * TXT_SCREEN_W + x * 5 + 3) * 2] = n;
}
}
TXT_UpdateScreen();
}
void TXT_SetPeriodicCallback(TxtIdleCallback callback,
void *user_data,
unsigned int period)
{
periodic_callback = callback;
periodic_callback_data = user_data;
periodic_callback_period = period;
}
void TXT_GUIMainLoop(void)
{
main_loop_running = 1;
while (main_loop_running)
{
TXT_DispatchEvents();
// After the last window is closed, exit the loop
if (num_windows <= 0)
{
TXT_ExitMainLoop();
continue;
}
TXT_DrawDesktop();
// TXT_DrawASCIITable();
if (periodic_callback == NULL)
{
TXT_Sleep(0);
}
else
{
TXT_Sleep(periodic_callback_period);
periodic_callback(periodic_callback_data);
}
}
}
@@ -0,0 +1,116 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_DESKTOP_H
#define TXT_DESKTOP_H
/**
* @file txt_desktop.h
*
* Textscreen desktop.
*/
#include "txt_window.h"
typedef void (*TxtIdleCallback)(void *user_data);
void TXT_AddDesktopWindow(txt_window_t *win);
void TXT_RemoveDesktopWindow(txt_window_t *win);
void TXT_DrawDesktop(void);
void TXT_DispatchEvents(void);
void TXT_DrawWindow(txt_window_t *window);
void TXT_SetWindowFocus(txt_window_t *window, int focused);
int TXT_WindowKeyPress(txt_window_t *window, int c);
/**
* Set the title displayed at the top of the screen.
*
* @param title The title to display (UTF-8 format).
*/
void TXT_SetDesktopTitle(const char *title);
/**
* Set the help title displayed at the bottom of the screen.
*
* @param title The title to display (UTF-8 format).
*/
void TXT_DrawHelpLabel(const char* title);
/**
* Exit the currently-running main loop and return from the
* @ref TXT_GUIMainLoop function.
*/
void TXT_ExitMainLoop(void);
/**
* Start the main event loop. At least one window must have been
* opened prior to running this function. When no windows are left
* open, the event loop exits.
*
* It is possible to trigger an exit from this function using the
* @ref TXT_ExitMainLoop function.
*/
void TXT_GUIMainLoop(void);
/**
* Get the top window on the desktop that is currently receiving
* inputs.
*
* @return The active window, or NULL if no windows are present.
*/
txt_window_t *TXT_GetActiveWindow(void);
/**
* Set a callback function to be invoked periodically by the main
* loop code.
*
* @param callback The callback to invoke, or NULL to cancel
* an existing callback.
* @param user_data Extra data to pass to the callback.
* @param period Maximum time between invoking each callback.
* eg. a value of 200 will cause the callback
* to be invoked at least once every 200ms.
*/
void TXT_SetPeriodicCallback(TxtIdleCallback callback,
void *user_data,
unsigned int period);
/**
* Raise the z-position of the given window relative to other windows.
*
* @param window The window to raise.
* @return Non-zero if the window was raised successfully,
* or zero if the window could not be raised further.
*/
int TXT_RaiseWindow(txt_window_t *window);
/**
* Lower the z-position of the given window relative to other windows.
*
* @param window The window to make inactive.
* @return Non-zero if the window was lowered successfully,
* or zero if the window could not be lowered further.
*/
int TXT_LowerWindow(txt_window_t *window);
#endif /* #ifndef TXT_DESKTOP_H */
@@ -0,0 +1,305 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_button.h"
#include "txt_dropdown.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
typedef struct
{
txt_window_t *window;
txt_dropdown_list_t *list;
int item;
} callback_data_t;
// Check if the selected value for a list is valid
static int ValidSelection(txt_dropdown_list_t *list)
{
return *list->variable >= 0 && *list->variable < list->num_values;
}
// Calculate the Y position for the selector window
static int SelectorWindowY(txt_dropdown_list_t *list)
{
int result;
if (ValidSelection(list))
{
result = list->widget.y - 1 - *list->variable;
}
else
{
result = list->widget.y - 1 - (list->num_values / 2);
}
// Keep dropdown inside the screen.
if (result < 1)
{
result = 1;
}
else if (result + list->num_values > (TXT_SCREEN_H - 3))
{
result = TXT_SCREEN_H - list->num_values - 3;
}
return result;
}
// Called when a button in the selector window is pressed
static void ItemSelected(TXT_UNCAST_ARG(button), TXT_UNCAST_ARG(callback_data))
{
TXT_CAST_ARG(callback_data_t, callback_data);
// Set the variable
*callback_data->list->variable = callback_data->item;
TXT_EmitSignal(callback_data->list, "changed");
// Close the window
TXT_CloseWindow(callback_data->window);
}
// Free callback data when the window is closed
static void FreeCallbackData(TXT_UNCAST_ARG(list),
TXT_UNCAST_ARG(callback_data))
{
TXT_CAST_ARG(callback_data_t, callback_data);
free(callback_data);
}
// Catch presses of escape and close the window.
static int SelectorWindowListener(txt_window_t *window, int key, void *user_data)
{
if (key == KEY_ESCAPE)
{
TXT_CloseWindow(window);
return 1;
}
return 0;
}
static int SelectorMouseListener(txt_window_t *window, int x, int y, int b,
void *unused)
{
txt_widget_t *win;
win = (txt_widget_t *) window;
if (x < win->x || x > win->x + win->w || y < win->y || y > win->y + win->h)
{
TXT_CloseWindow(window);
return 1;
}
return 0;
}
// Open the dropdown list window to select an item
static void OpenSelectorWindow(txt_dropdown_list_t *list)
{
txt_window_t *window;
int i;
// Open a simple window with no title bar or action buttons.
window = TXT_NewWindow(NULL);
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
TXT_SetWindowAction(window, TXT_HORIZ_CENTER, NULL);
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
// Position the window so that the currently selected item appears
// over the top of the list widget.
TXT_SetWindowPosition(window, TXT_HORIZ_LEFT, TXT_VERT_TOP,
list->widget.x - 2, SelectorWindowY(list));
// Add a button to the window for each option in the list.
for (i=0; i<list->num_values; ++i)
{
txt_button_t *button;
callback_data_t *data;
button = TXT_NewButton(list->values[i]);
TXT_AddWidget(window, button);
// Callback struct
data = malloc(sizeof(callback_data_t));
data->list = list;
data->window = window;
data->item = i;
// When the button is pressed, invoke the button press callback
TXT_SignalConnect(button, "pressed", ItemSelected, data);
// When the window is closed, free back the callback struct
TXT_SignalConnect(window, "closed", FreeCallbackData, data);
// Is this the currently-selected value? If so, select the button
// in the window as the default.
if (i == *list->variable)
{
TXT_SelectWidget(window, button);
}
}
// Catch presses of escape in this window and close it.
TXT_SetKeyListener(window, SelectorWindowListener, NULL);
TXT_SetMouseListener(window, SelectorMouseListener, NULL);
}
static int DropdownListWidth(txt_dropdown_list_t *list)
{
int i;
int result;
// Find the maximum string width
result = 0;
for (i=0; i<list->num_values; ++i)
{
int w = TXT_UTF8_Strlen(list->values[i]);
if (w > result)
{
result = w;
}
}
return result;
}
static void TXT_DropdownListSizeCalc(TXT_UNCAST_ARG(list))
{
TXT_CAST_ARG(txt_dropdown_list_t, list);
list->widget.w = DropdownListWidth(list);
list->widget.h = 1;
}
static void TXT_DropdownListDrawer(TXT_UNCAST_ARG(list))
{
TXT_CAST_ARG(txt_dropdown_list_t, list);
unsigned int i;
const char *str;
// Set bg/fg text colors.
TXT_SetWidgetBG(list);
// Select a string to draw from the list, if the current value is
// in range. Otherwise fall back to a default.
if (ValidSelection(list))
{
str = list->values[*list->variable];
}
else
{
str = "???";
}
// Draw the string and fill to the end with spaces
TXT_DrawString(str);
for (i = TXT_UTF8_Strlen(str); i < list->widget.w; ++i)
{
TXT_DrawString(" ");
}
}
static void TXT_DropdownListDestructor(TXT_UNCAST_ARG(list))
{
}
static int TXT_DropdownListKeyPress(TXT_UNCAST_ARG(list), int key)
{
TXT_CAST_ARG(txt_dropdown_list_t, list);
if (key == KEY_ENTER)
{
OpenSelectorWindow(list);
return 1;
}
return 0;
}
static void TXT_DropdownListMousePress(TXT_UNCAST_ARG(list),
int x, int y, int b)
{
TXT_CAST_ARG(txt_dropdown_list_t, list);
// Left mouse click does the same as selecting and pressing enter
if (b == TXT_MOUSE_LEFT)
{
TXT_DropdownListKeyPress(list, KEY_ENTER);
}
}
txt_widget_class_t txt_dropdown_list_class =
{
TXT_AlwaysSelectable,
TXT_DropdownListSizeCalc,
TXT_DropdownListDrawer,
TXT_DropdownListKeyPress,
TXT_DropdownListDestructor,
TXT_DropdownListMousePress,
NULL,
};
txt_dropdown_list_t *TXT_NewDropdownList(int *variable, const char **values,
int num_values)
{
txt_dropdown_list_t *list;
list = malloc(sizeof(txt_dropdown_list_t));
TXT_InitWidget(list, &txt_dropdown_list_class);
list->variable = variable;
list->values = values;
list->num_values = num_values;
return list;
}
@@ -0,0 +1,69 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_DROPDOWN_H
#define TXT_DROPDOWN_H
/**
* @file txt_dropdown.h
*
* Dropdown list widget.
*/
/**
* Dropdown list widget.
*
* A dropdown list allows the user to select from a list of values,
* which appears when the list is selected.
*
* When the value of a dropdown list is changed, the "changed" signal
* is emitted.
*/
typedef struct txt_dropdown_list_s txt_dropdown_list_t;
#include "txt_widget.h"
//
// Drop-down list box.
//
struct txt_dropdown_list_s
{
txt_widget_t widget;
int *variable;
const char **values;
int num_values;
};
/**
* Create a new dropdown list widget.
*
* The parameters specify a list of string labels, and a pointer to an
* integer variable. The variable contains the current "value" of the
* list, as an index within the list of labels.
*
* @param variable Pointer to the variable containing the
* list's value.
* @param values Pointer to an array of strings containing
* the labels to use for the list (UTF-8 format).
* @param num_values The number of variables in the list.
*/
txt_dropdown_list_t *TXT_NewDropdownList(int *variable,
const char **values, int num_values);
#endif /* #ifndef TXT_DROPDOWN_H */
@@ -0,0 +1,840 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Routines for selecting files.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "doomkeys.h"
#include "txt_fileselect.h"
#include "txt_inputbox.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_widget.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
struct txt_fileselect_s {
txt_widget_t widget;
txt_inputbox_t *inputbox;
int size;
const char *prompt;
const char **extensions;
};
// Dummy value to select a directory.
const char *TXT_DIRECTORY[] = { "__directory__", NULL };
#ifndef _WIN32
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>
static char *ExecReadOutput(char **argv)
{
char *result;
int completed;
int pid, status, result_len;
int pipefd[2];
if (pipe(pipefd) != 0)
{
return NULL;
}
pid = fork();
if (pid == 0)
{
dup2(pipefd[1], fileno(stdout));
execv(argv[0], argv);
exit(-1);
}
fcntl(pipefd[0], F_SETFL, O_NONBLOCK);
// Read program output into 'result' string.
// Wait until the program has completed and (if it was successful)
// a full line has been read.
result = NULL;
result_len = 0;
completed = 0;
while (!completed
|| (status == 0 && (result == NULL || strchr(result, '\n') == NULL)))
{
char buf[64];
int bytes;
if (!completed && waitpid(pid, &status, WNOHANG) != 0)
{
completed = 1;
}
bytes = read(pipefd[0], buf, sizeof(buf));
if (bytes < 0)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
{
status = -1;
break;
}
}
else
{
char *new_result = realloc(result, result_len + bytes + 1);
if (new_result == NULL)
{
break;
}
result = new_result;
memcpy(result + result_len, buf, bytes);
result_len += bytes;
result[result_len] = '\0';
}
usleep(100 * 1000);
TXT_Sleep(1);
TXT_UpdateScreen();
}
close(pipefd[0]);
close(pipefd[1]);
// Must have a success exit code.
if (WEXITSTATUS(status) != 0)
{
free(result);
result = NULL;
}
// Strip off newline from the end.
if (result != NULL && result[result_len - 1] == '\n')
{
result[result_len - 1] = '\0';
}
return result;
}
#endif
// This is currently disabled on Windows because it doesn't work.
// Current issues:
// * On Windows Vista+ the mouse cursor freezes when the dialog is
// opened. This is probably some conflict with SDL (might be
// resolved by opening the dialog in a separate thread so that
// TXT_UpdateScreen can be run in the background).
// * On Windows XP the program exits/crashes when the dialog is
// closed.
#if defined(_WIN32)
int TXT_CanSelectFiles(void)
{
return 0;
}
char *TXT_SelectFile(const char *window_title, const char **extensions)
{
return NULL;
}
#elif defined(xxxdisabled_WIN32)
// Windows code. Use comdlg32 to pop up a dialog box.
#include <windows.h>
#include <shlobj.h>
static BOOL (*MyGetOpenFileName)(LPOPENFILENAME) = NULL;
static LPITEMIDLIST (*MySHBrowseForFolder)(LPBROWSEINFO) = NULL;
static BOOL (*MySHGetPathFromIDList)(LPITEMIDLIST, LPTSTR) = NULL;
// Load library functions from DLL files.
static int LoadDLLs(void)
{
HMODULE comdlg32, shell32
comdlg32 = LoadLibraryW(L"comdlg32.dll");
if (comdlg32 == NULL)
{
return 0;
}
shell32 = LoadLibraryW(L"shell32.dll");
if (shell32 == NULL)
{
FreeLibrary(comdlg32);
return 0;
}
MyGetOpenFileName =
(void *) GetProcAddress(comdlg32, "GetOpenFileNameA");
MySHBrowseForFolder =
(void *) GetProcAddress(shell32, "SHBrowseForFolder");
MySHGetPathFromIDList =
(void *) GetProcAddress(shell32, "SHGetPathFromIDList");
return MyGetOpenFileName != NULL
&& MySHBrowseForFolder != NULL
&& MySHGetPathFromIDList != NULL;
}
static int InitLibraries(void)
{
static int initted = 0, success = 0;
if (!initted)
{
success = LoadDLLs();
initted = 1;
}
return success;
}
// Generate the "filter" string from the list of extensions.
static char *GenerateFilterString(const char **extensions)
{
unsigned int result_len = 1;
unsigned int i;
char *result, *out;
size_t out_len, offset;
if (extensions == NULL)
{
return NULL;
}
for (i = 0; extensions[i] != NULL; ++i)
{
result_len += 16 + strlen(extensions[i]) * 3;
}
result = malloc(result_len);
out = result; out_len = result_len;
for (i = 0; extensions[i] != NULL; ++i)
{
// .wad files (*.wad)\0
offset = TXT_snprintf(out, out_len, "%s files (*.%s)",
extensions[i], extensions[i]);
out += offset + 1; out_len -= offset + 1;
// *.wad\0
offset = TXT_snprintf(out, out_len, "*.%s", extensions[i]);
out_len += offset + 1; out_len -= offset + 1;
}
*out = '\0';
return result;
}
int TXT_CanSelectFiles(void)
{
return InitLibraries();
}
static char *SelectDirectory(char *window_title)
{
LPITEMIDLIST pidl;
BROWSEINFO bi;
char selected[MAX_PATH] = "";
char *result;
ZeroMemory(&bi, sizeof(bi));
bi.hwndOwner = NULL;
bi.lpszTitle = window_title;
bi.pszDisplayName = selected;
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
pidl = MySHBrowseForFolder(&bi);
result = NULL;
if (pidl != NULL)
{
if (MySHGetPathFromIDList(pidl, selected))
{
result = strdup(selected);
}
// TODO: Free pidl
}
return result;
}
char *TXT_SelectFile(const char *window_title, const char **extensions)
{
OPENFILENAME fm;
char selected[MAX_PATH] = "";
char *filter_string, *result;
if (!InitLibraries())
{
return NULL;
}
if (extensions == TXT_DIRECTORY)
{
return SelectDirectory(window_title);
}
filter_string = GenerateFilterString(extensions);
ZeroMemory(&fm, sizeof(fm));
fm.lStructSize = sizeof(OPENFILENAME);
fm.hwndOwner = NULL;
fm.lpstrTitle = window_title;
fm.lpstrFilter = filter_string;
fm.lpstrFile = selected;
fm.nMaxFile = MAX_PATH;
fm.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
fm.lpstrDefExt = "";
if (!MyGetOpenFileName(&fm))
{
result = NULL;
}
else
{
result = strdup(selected);
}
free(filter_string);
return result;
}
#elif defined(__MACOSX__)
// Mac OS X code. Popping up a dialog requires Objective C/Cocoa
// but we can get away with using AppleScript which avoids adding
// an Objective C dependency. This is rather silly.
// Printf format string for the "wrapper" portion of the AppleScript:
#define APPLESCRIPT_WRAPPER "copy POSIX path of (%s) to stdout"
static char *CreateEscapedString(const char *original)
{
char *result;
const char *in;
char *out;
// We need to take care not to overflow the buffer, so count exactly.
#define ESCAPED_CHARS "\"\\"
size_t count_extras = 2; // start counting the two quotes
for (in = original; *in; ++in)
{
if (strchr(ESCAPED_CHARS, *in))
{
++count_extras;
}
}
result = malloc(strlen(original) + count_extras + 1);
if (!result)
{
return NULL;
}
out = result;
*out++ = '"';
for (in = original; *in; ++in)
{
if (strchr(ESCAPED_CHARS, *in))
{
*out++ = '\\';
}
*out++ = *in;
}
*out++ = '"';
*out = 0;
return result;
#undef ESCAPED_CHARS
}
// Build list of extensions, like: {"wad","lmp","txt"}
static char *CreateExtensionsList(const char **extensions)
{
char *result, *escaped;
unsigned int result_len;
unsigned int i;
if (extensions == NULL)
{
return NULL;
}
result_len = 3;
for (i = 0; extensions[i] != NULL; ++i)
{
result_len += 5 + strlen(extensions[i]) * 2;
}
result = malloc(result_len);
if (!result)
{
return NULL;
}
TXT_StringCopy(result, "{", result_len);
for (i = 0; extensions[i] != NULL; ++i)
{
escaped = CreateEscapedString(extensions[i]);
if (!escaped)
{
free(result);
return NULL;
}
TXT_StringConcat(result, escaped, result_len);
free(escaped);
if (extensions[i + 1] != NULL)
{
TXT_StringConcat(result, ",", result_len);
}
}
TXT_StringConcat(result, "}", result_len);
return result;
}
static char *GenerateSelector(const char *const window_title, const char **extensions)
{
const char *chooser;
char *ext_list = NULL;
char *window_title_escaped = NULL;
char *result = NULL;
unsigned int result_len = 64;
if (extensions == TXT_DIRECTORY)
{
chooser = "choose folder";
}
else
{
chooser = "choose file";
ext_list = CreateExtensionsList(extensions);
if (!ext_list)
{
return NULL;
}
}
// Calculate size.
if (window_title != NULL)
{
window_title_escaped = CreateEscapedString(window_title);
if (!window_title_escaped)
{
free(ext_list);
return NULL;
}
result_len += strlen(window_title_escaped);
}
if (ext_list != NULL)
{
result_len += strlen(ext_list);
}
result = malloc(result_len);
if (!result)
{
free(window_title_escaped);
free(ext_list);
return NULL;
}
TXT_StringCopy(result, chooser, result_len);
if (window_title_escaped != NULL)
{
TXT_StringConcat(result, " with prompt ", result_len);
TXT_StringConcat(result, window_title_escaped, result_len);
}
if (ext_list != NULL)
{
TXT_StringConcat(result, " of type ", result_len);
TXT_StringConcat(result, ext_list, result_len);
}
free(window_title_escaped);
free(ext_list);
return result;
}
static char *GenerateAppleScript(const char *window_title, const char **extensions)
{
char *selector, *result;
size_t result_len;
selector = GenerateSelector(window_title, extensions);
if (!selector)
{
return NULL;
}
result_len = strlen(APPLESCRIPT_WRAPPER) + strlen(selector);
result = malloc(result_len);
if (!result)
{
free(selector);
return NULL;
}
TXT_snprintf(result, result_len, APPLESCRIPT_WRAPPER, selector);
free(selector);
return result;
}
int TXT_CanSelectFiles(void)
{
return 1;
}
char *TXT_SelectFile(const char *window_title, const char **extensions)
{
char *argv[4];
char *result, *applescript;
applescript = GenerateAppleScript(window_title, extensions);
if (!applescript)
{
return NULL;
}
argv[0] = "/usr/bin/osascript";
argv[1] = "-e";
argv[2] = applescript;
argv[3] = NULL;
result = ExecReadOutput(argv);
free(applescript);
return result;
}
#else
// Linux version: invoke the Zenity command line program to pop up a
// dialog box. This avoids adding Gtk+ as a compile dependency.
#define ZENITY_BINARY "/usr/bin/zenity"
static unsigned int NumExtensions(const char **extensions)
{
unsigned int result = 0;
if (extensions != NULL)
{
for (result = 0; extensions[result] != NULL; ++result);
}
return result;
}
static int ZenityAvailable(void)
{
return system(ZENITY_BINARY " --help >/dev/null 2>&1") == 0;
}
int TXT_CanSelectFiles(void)
{
return ZenityAvailable();
}
//
// ExpandExtension
// given an extension (like wad)
// return a pointer to a string that is a case-insensitive
// pattern representation (like [Ww][Aa][Dd])
//
static char *ExpandExtension(const char *orig)
{
int oldlen, newlen, i;
char *c, *newext = NULL;
oldlen = strlen(orig);
newlen = oldlen * 4; // pathological case: 'w' => '[Ww]'
newext = malloc(newlen+1);
if (newext == NULL)
{
return NULL;
}
c = newext;
for (i = 0; i < oldlen; ++i)
{
if (isalpha(orig[i]))
{
*c++ = '[';
*c++ = tolower(orig[i]);
*c++ = toupper(orig[i]);
*c++ = ']';
}
else
{
*c++ = orig[i];
}
}
*c = '\0';
return newext;
}
char *TXT_SelectFile(const char *window_title, const char **extensions)
{
unsigned int i;
size_t len;
char *result;
char **argv;
int argc;
if (!ZenityAvailable())
{
return NULL;
}
argv = calloc(5 + NumExtensions(extensions), sizeof(char *));
argv[0] = strdup(ZENITY_BINARY);
argv[1] = strdup("--file-selection");
argc = 2;
if (window_title != NULL)
{
len = 10 + strlen(window_title);
argv[argc] = malloc(len);
TXT_snprintf(argv[argc], len, "--title=%s", window_title);
++argc;
}
if (extensions == TXT_DIRECTORY)
{
argv[argc] = strdup("--directory");
++argc;
}
else if (extensions != NULL)
{
for (i = 0; extensions[i] != NULL; ++i)
{
char * newext = ExpandExtension(extensions[i]);
if (newext)
{
len = 30 + strlen(extensions[i]) + strlen(newext);
argv[argc] = malloc(len);
TXT_snprintf(argv[argc], len, "--file-filter=.%s | *.%s",
extensions[i], newext);
++argc;
free(newext);
}
}
argv[argc] = strdup("--file-filter=*.* | *.*");
++argc;
}
argv[argc] = NULL;
result = ExecReadOutput(argv);
for (i = 0; i < argc; ++i)
{
free(argv[i]);
}
free(argv);
return result;
}
#endif
static void TXT_FileSelectSizeCalc(TXT_UNCAST_ARG(fileselect))
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
// Calculate widget size, but override the width to always
// be the configured size.
TXT_CalcWidgetSize(fileselect->inputbox);
fileselect->widget.w = fileselect->size;
fileselect->widget.h = fileselect->inputbox->widget.h;
}
static void TXT_FileSelectDrawer(TXT_UNCAST_ARG(fileselect))
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
// Input box widget inherits all the properties of the
// file selector.
fileselect->inputbox->widget.x = fileselect->widget.x + 2;
fileselect->inputbox->widget.y = fileselect->widget.y;
fileselect->inputbox->widget.w = fileselect->widget.w - 2;
fileselect->inputbox->widget.h = fileselect->widget.h;
// Triple bar symbol gives a distinguishing look to the file selector.
TXT_DrawCodePageString("\xf0 ");
TXT_BGColor(TXT_COLOR_BLACK, 0);
TXT_DrawWidget(fileselect->inputbox);
}
static void TXT_FileSelectDestructor(TXT_UNCAST_ARG(fileselect))
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
TXT_DestroyWidget(fileselect->inputbox);
}
static int DoSelectFile(txt_fileselect_t *fileselect)
{
char *path;
char **var;
if (TXT_CanSelectFiles())
{
path = TXT_SelectFile(fileselect->prompt,
fileselect->extensions);
// Update inputbox variable.
// If cancel was pressed (ie. NULL was returned by TXT_SelectFile)
// then reset to empty string, not NULL).
if (path == NULL)
{
path = strdup("");
}
var = fileselect->inputbox->value;
free(*var);
*var = path;
return 1;
}
return 0;
}
static int TXT_FileSelectKeyPress(TXT_UNCAST_ARG(fileselect), int key)
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
// When the enter key is pressed, pop up a file selection dialog,
// if file selectors work. Allow holding down 'alt' to override
// use of the native file selector, so the user can just type a path.
if (!fileselect->inputbox->editing
&& !TXT_GetModifierState(TXT_MOD_ALT)
&& key == KEY_ENTER)
{
if (DoSelectFile(fileselect))
{
return 1;
}
}
return TXT_WidgetKeyPress(fileselect->inputbox, key);
}
static void TXT_FileSelectMousePress(TXT_UNCAST_ARG(fileselect),
int x, int y, int b)
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
if (!fileselect->inputbox->editing
&& !TXT_GetModifierState(TXT_MOD_ALT)
&& b == TXT_MOUSE_LEFT)
{
if (DoSelectFile(fileselect))
{
return;
}
}
TXT_WidgetMousePress(fileselect->inputbox, x, y, b);
}
static void TXT_FileSelectFocused(TXT_UNCAST_ARG(fileselect), int focused)
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
TXT_SetWidgetFocus(fileselect->inputbox, focused);
}
txt_widget_class_t txt_fileselect_class =
{
TXT_AlwaysSelectable,
TXT_FileSelectSizeCalc,
TXT_FileSelectDrawer,
TXT_FileSelectKeyPress,
TXT_FileSelectDestructor,
TXT_FileSelectMousePress,
NULL,
TXT_FileSelectFocused,
};
// If the (inner) inputbox widget is changed, emit a change to the
// outer (fileselect) widget.
static void InputBoxChanged(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(fileselect))
{
TXT_CAST_ARG(txt_fileselect_t, fileselect);
TXT_EmitSignal(&fileselect->widget, "changed");
}
txt_fileselect_t *TXT_NewFileSelector(char **variable, int size,
const char *prompt, const char **extensions)
{
txt_fileselect_t *fileselect;
fileselect = malloc(sizeof(txt_fileselect_t));
TXT_InitWidget(fileselect, &txt_fileselect_class);
fileselect->inputbox = TXT_NewInputBox(variable, 1024);
fileselect->inputbox->widget.parent = &fileselect->widget;
fileselect->size = size;
fileselect->prompt = prompt;
fileselect->extensions = extensions;
TXT_SignalConnect(fileselect->inputbox, "changed",
InputBoxChanged, fileselect);
return fileselect;
}
@@ -0,0 +1,79 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Routines for selecting files, and the txt_fileselect_t widget.
//
#ifndef TXT_FILESELECT_H
#define TXT_FILESELECT_H
/**
* @file txt_fileselect.h
*
* File selection widget.
*/
/**
* File selection widget.
*
* A file selection widget resembles an input box (@ref txt_inputbox_t)
* but opens a file selector dialog box when clicked.
*/
typedef struct txt_fileselect_s txt_fileselect_t;
/**
* Returns non-zero if a native file selector is available on this
* platform.
*/
int TXT_CanSelectFiles(void);
/**
* Open a native file selector to select a file.
*
* @param prompt Pointer to a string containing a prompt to display
* in the window.
* @param extensions NULL-terminated list of filename extensions for
* files that can be selected, or @ref TXT_DIRECTORY
* to select directories.
*/
char *TXT_SelectFile(const char *prompt, const char **extensions);
/**
* Create a new txt_fileselect_t widget.
*
* @param variable Pointer to a char * variable in which the selected
* file should be stored (UTF-8 format).
* @param size Width of the file selector widget in characters.
* @param prompt Pointer to a string containing a prompt to display
* in the file selection window.
* @param extensions NULL-terminated list of filename extensions that
* can be used for this widget, or @ref TXT_DIRECTORY
* to select directories.
*/
txt_fileselect_t *TXT_NewFileSelector(char **variable, int size,
const char *prompt, const char **extensions);
/**
* Special value to use for 'extensions' that selects a directory
* instead of a file.
*/
extern const char *TXT_DIRECTORY[];
#endif /* #ifndef TXT_FILESELECT_H */
+556
View File
@@ -0,0 +1,556 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
typedef struct txt_cliparea_s txt_cliparea_t;
struct txt_cliparea_s
{
int x1, x2;
int y1, y2;
txt_cliparea_t *next;
};
// Array of border characters for drawing windows. The array looks like this:
//
// +-++
// | ||
// +-++
// +-++
static const int borders[4][4] =
{
{0xda, 0xc4, 0xc2, 0xbf},
{0xb3, ' ', 0xb3, 0xb3},
{0xc3, 0xc4, 0xc5, 0xb4},
{0xc0, 0xc4, 0xc1, 0xd9},
};
static txt_cliparea_t *cliparea = NULL;
#define VALID_X(x) ((x) >= cliparea->x1 && (x) < cliparea->x2)
#define VALID_Y(y) ((y) >= cliparea->y1 && (y) < cliparea->y2)
void TXT_DrawDesktopBackground(const char *title)
{
int i;
unsigned char *screendata;
unsigned char *p;
screendata = TXT_GetScreenData();
// Fill the screen with gradient characters
p = screendata;
for (i=0; i<TXT_SCREEN_W * TXT_SCREEN_H; ++i)
{
*p++ = 0xb1;
*p++ = TXT_COLOR_GREY | (TXT_COLOR_BLUE << 4);
}
// Draw the top and bottom banners
p = screendata;
for (i = 0; i<TXT_SCREEN_W; ++i)
{
*p++ = ' ';
*p++ = TXT_COLOR_BLACK | (TXT_COLOR_GREY << 4);
}
p = screendata + (TXT_SCREEN_H - 1) * TXT_SCREEN_W * 2;
for (i = 0; i<TXT_SCREEN_W; ++i)
{
*p++ = ' ';
*p++ = TXT_COLOR_BLACK | (TXT_COLOR_GREY << 4);
}
// Print the title
TXT_GotoXY(0, 0);
TXT_FGColor(TXT_COLOR_BLACK);
TXT_BGColor(TXT_COLOR_GREY, 0);
TXT_DrawString(" ");
TXT_DrawString(title);
}
void TXT_DrawShadow(int x, int y, int w, int h)
{
unsigned char *screendata;
unsigned char *p;
int x1, y1;
screendata = TXT_GetScreenData();
for (y1=y; y1<y+h; ++y1)
{
p = screendata + (y1 * TXT_SCREEN_W + x) * 2;
for (x1=x; x1<x+w; ++x1)
{
if (VALID_X(x1) && VALID_Y(y1))
{
p[1] = TXT_COLOR_DARK_GREY;
}
p += 2;
}
}
}
void TXT_DrawWindowFrame(const char *title, int x, int y, int w, int h, int titlecolor, int framecolor, int customwin)
{
txt_saved_colors_t colors;
int x1, y1;
int bx, by;
TXT_SaveColors(&colors);
if (customwin == 1)
{
TXT_FGColor(framecolor);
}
else
{
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
}
for (y1=y; y1<y+h; ++y1)
{
// Select the appropriate row and column in the borders
// array to pick the appropriate character to draw at
// this location.
//
// Draw a horizontal line on the third line down, so we
// draw a box around the title.
by = y1 == y ? 0 :
y1 == y + 2 && title != NULL ? 2 :
y1 == y + h - 1 ? 3 : 1;
for (x1=x; x1<x+w; ++x1)
{
bx = x1 == x ? 0 :
x1 == x + w - 1 ? 3 : 1;
if (VALID_X(x1) && VALID_Y(y1))
{
TXT_GotoXY(x1, y1);
TXT_PutChar(borders[by][bx]);
}
}
}
// Draw the title
if (title != NULL)
{
TXT_GotoXY(x + 1, y + 1);
TXT_BGColor(TXT_COLOR_GREY, 0);
if (customwin == 1)
{
TXT_FGColor(titlecolor);
}
else
{
TXT_FGColor(TXT_COLOR_BLUE);
}
for (x1=0; x1<w-2; ++x1)
{
TXT_DrawString(" ");
}
TXT_GotoXY(x + (w - TXT_UTF8_Strlen(title)) / 2, y + 1);
TXT_DrawString(title);
}
// Draw the window's shadow.
TXT_DrawShadow(x + 2, y + h, w, 1);
TXT_DrawShadow(x + w, y + 1, 2, h);
TXT_RestoreColors(&colors);
}
void TXT_DrawSpecialSeparator(int x, int y, int w, int h, int sepcolor, int customwin)
{
txt_saved_colors_t colors;
int y1;
int by;
int bx;
int x1;
int b;
TXT_SaveColors(&colors);
if (customwin == 1)
{
TXT_FGColor(sepcolor);
}
else
{
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
}
if (!VALID_Y(y))
{
return;
}
for (y1 = y; y1 < y + h; ++y1)
{
// Select the appropriate row and column in the borders
// array to pick the appropriate character to draw at
// this location.
by = y1 == y ? 0 :
y1 == y + h - 1 ? 3 : 1;
for (x1 = x; x1 < x + w; ++x1)
{
bx = x1 == x ? 0 :
x1 == x + w - 1 ? 3 : 1;
if (VALID_X(x1) && VALID_Y(y1))
{
TXT_GotoXY(x1, y1);
TXT_PutChar(borders[by][bx]);
}
}
}
TXT_RestoreColors(&colors);
}
void TXT_DrawSeparator(int x, int y, int w, int sepcolor, int customwin)
{
txt_saved_colors_t colors;
unsigned char *data;
int x1;
int b;
data = TXT_GetScreenData();
TXT_SaveColors(&colors);
if (customwin == 1)
{
TXT_FGColor(sepcolor);
}
else
{
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
}
if (!VALID_Y(y))
{
return;
}
data += (y * TXT_SCREEN_W + x) * 2;
for (x1=x; x1<x+w; ++x1)
{
TXT_GotoXY(x1, y);
b = x1 == x ? 0 :
x1 == x + w - 1 ? 3 :
1;
if (VALID_X(x1))
{
// Read the current value from the screen
// Check that it matches what the window should look like if
// there is no separator, then apply the separator
if (*data == borders[1][b])
{
TXT_PutChar(borders[2][b]);
}
}
data += 2;
}
TXT_RestoreColors(&colors);
}
// Alternative to TXT_DrawString() where the argument is a "code page
// string" - characters are in native code page format and not UTF-8.
void TXT_DrawCodePageString(const char *s)
{
int x, y;
int x1;
const char *p;
TXT_GetXY(&x, &y);
if (VALID_Y(y))
{
x1 = x;
for (p = s; *p != '\0'; ++p)
{
if (VALID_X(x1))
{
TXT_GotoXY(x1, y);
TXT_PutChar(*p);
}
x1 += 1;
}
}
TXT_GotoXY(x + strlen(s), y);
}
static void PutUnicodeChar(unsigned int c)
{
int d;
// Treat control characters specially.
if (c == '\n' || c == '\b')
{
TXT_PutChar(c);
return;
}
// Map Unicode character into the symbol used to represent it in this
// code page. For unrepresentable characters, print a fallback instead.
// Note that we use TXT_PutSymbol() here because we just want to do a
// raw write into the screen buffer.
d = TXT_UnicodeCharacter(c);
if (d >= 0)
{
TXT_PutSymbol(d);
}
else
{
TXT_PutSymbol('\xa8');
}
}
void TXT_DrawString(const char *s)
{
int x, y;
int x1;
const char *p;
unsigned int c;
TXT_GetXY(&x, &y);
if (VALID_Y(y))
{
x1 = x;
for (p = s; *p != '\0'; )
{
c = TXT_DecodeUTF8(&p);
if (c == 0)
{
break;
}
if (VALID_X(x1))
{
TXT_GotoXY(x1, y);
PutUnicodeChar(c);
}
x1 += 1;
}
}
TXT_GotoXY(x + TXT_UTF8_Strlen(s), y);
}
void TXT_DrawHorizScrollbar(int x, int y, int w, int cursor, int range)
{
txt_saved_colors_t colors;
int x1;
int cursor_x;
if (!VALID_Y(y))
{
return;
}
TXT_SaveColors(&colors);
TXT_FGColor(TXT_COLOR_BLACK);
TXT_BGColor(TXT_COLOR_GREY, 0);
TXT_GotoXY(x, y);
TXT_PutChar('\x1b');
cursor_x = x + 1;
if (range > 0)
{
cursor_x += (cursor * (w - 3)) / range;
}
if (cursor_x > x + w - 2)
{
cursor_x = x + w - 2;
}
for (x1=x+1; x1<x+w-1; ++x1)
{
if (VALID_X(x1))
{
if (x1 == cursor_x)
{
TXT_PutChar('\xdb');
}
else
{
TXT_PutChar('\xb1');
}
}
}
TXT_PutChar('\x1a');
TXT_RestoreColors(&colors);
}
void TXT_DrawVertScrollbar(int x, int y, int h, int cursor, int range)
{
txt_saved_colors_t colors;
int y1;
int cursor_y;
if (!VALID_X(x))
{
return;
}
TXT_SaveColors(&colors);
TXT_FGColor(TXT_COLOR_BLACK);
TXT_BGColor(TXT_COLOR_GREY, 0);
TXT_GotoXY(x, y);
TXT_PutChar('\x18');
cursor_y = y + 1;
if (cursor_y > y + h - 2)
{
cursor_y = y + h - 2;
}
if (range > 0)
{
cursor_y += (cursor * (h - 3)) / range;
}
for (y1=y+1; y1<y+h-1; ++y1)
{
if (VALID_Y(y1))
{
TXT_GotoXY(x, y1);
if (y1 == cursor_y)
{
TXT_PutChar('\xdb');
}
else
{
TXT_PutChar('\xb1');
}
}
}
TXT_GotoXY(x, y + h - 1);
TXT_PutChar('\x19');
TXT_RestoreColors(&colors);
}
void TXT_InitClipArea(void)
{
if (cliparea == NULL)
{
cliparea = malloc(sizeof(txt_cliparea_t));
cliparea->x1 = 0;
cliparea->x2 = TXT_SCREEN_W;
cliparea->y1 = 0;
cliparea->y2 = TXT_SCREEN_H;
cliparea->next = NULL;
}
}
void TXT_PushClipArea(int x1, int x2, int y1, int y2)
{
txt_cliparea_t *newarea;
newarea = malloc(sizeof(txt_cliparea_t));
// Set the new clip area to the intersection of the old
// area and the new one.
newarea->x1 = cliparea->x1;
newarea->x2 = cliparea->x2;
newarea->y1 = cliparea->y1;
newarea->y2 = cliparea->y2;
if (x1 > newarea->x1)
newarea->x1 = x1;
if (x2 < newarea->x2)
newarea->x2 = x2;
if (y1 > newarea->y1)
newarea->y1 = y1;
if (y2 < newarea->y2)
newarea->y2 = y2;
#if 0
printf("New scrollable area: %i,%i-%i,%i\n", x1, y1, x2, y2);
#endif
// Hook into the list
newarea->next = cliparea;
cliparea = newarea;
}
void TXT_PopClipArea(void)
{
txt_cliparea_t *next_cliparea;
// Never pop the last entry
if (cliparea->next == NULL)
return;
// Unlink the last entry and delete
next_cliparea = cliparea->next;
free(cliparea);
cliparea = next_cliparea;
}
@@ -0,0 +1,41 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Text mode emulation in SDL
//
#ifndef TXT_GUI_H
#define TXT_GUI_H
#define TXT_INACTIVE_WINDOW_BACKGROUND TXT_COLOR_BLACK
#define TXT_ACTIVE_WINDOW_BACKGROUND TXT_COLOR_BLUE
#define TXT_HOVER_BACKGROUND TXT_COLOR_CYAN
void TXT_DrawDesktopBackground(const char *title);
void TXT_DrawWindowFrame(const char *title, int x, int y, int w, int h, int titlecolor, int framecolor, int customwin);
void TXT_DrawSeparator(int x, int y, int w, int sepcolor, int customwin);
void TXT_DrawSpecialSeparator(int x, int y, int w, int h, int sepcolor, int customwin);
void TXT_DrawCodePageString(const char *s);
void TXT_DrawString(const char *s);
int TXT_CanDrawCharacter(unsigned int c);
void TXT_DrawHorizScrollbar(int x, int y, int w, int cursor, int range);
void TXT_DrawVertScrollbar(int x, int y, int h, int cursor, int range);
void TXT_InitClipArea(void);
void TXT_PushClipArea(int x1, int x2, int y1, int y2);
void TXT_PopClipArea(void);
#endif /* #ifndef TXT_GUI_H */
@@ -0,0 +1,387 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_inputbox.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
extern txt_widget_class_t txt_inputbox_class;
extern txt_widget_class_t txt_int_inputbox_class;
static void SetBufferFromValue(txt_inputbox_t *inputbox)
{
if (inputbox->widget.widget_class == &txt_inputbox_class)
{
char **value = (char **) inputbox->value;
if (*value != NULL)
{
TXT_StringCopy(inputbox->buffer, *value, strnlen(*value, inputbox->buffer_len) + 1);
}
else
{
TXT_StringCopy(inputbox->buffer, "", inputbox->buffer_len);
}
}
else if (inputbox->widget.widget_class == &txt_int_inputbox_class)
{
int *value = (int *) inputbox->value;
TXT_snprintf(inputbox->buffer, inputbox->buffer_len, "%i", *value);
}
}
static void StartEditing(txt_inputbox_t *inputbox)
{
// Integer input boxes start from an empty buffer:
if (inputbox->widget.widget_class == &txt_int_inputbox_class)
{
TXT_StringCopy(inputbox->buffer, "", inputbox->buffer_len);
}
else
{
SetBufferFromValue(inputbox);
}
// Switch to text input mode so we get shifted input.
TXT_SetInputMode(TXT_INPUT_TEXT);
inputbox->editing = 1;
}
static void StopEditing(txt_inputbox_t *inputbox)
{
if (inputbox->editing)
{
// Switch back to normal input mode.
TXT_SetInputMode(TXT_INPUT_NORMAL);
inputbox->editing = 0;
}
}
static void FinishEditing(txt_inputbox_t *inputbox)
{
if (!inputbox->editing)
{
return;
}
// Save the new value back to the variable.
if (inputbox->widget.widget_class == &txt_inputbox_class)
{
free(*((char **)inputbox->value));
*((char **) inputbox->value) = strdup(inputbox->buffer);
}
else if (inputbox->widget.widget_class == &txt_int_inputbox_class)
{
*((int *) inputbox->value) = atoi(inputbox->buffer);
}
TXT_EmitSignal(&inputbox->widget, "changed");
StopEditing(inputbox);
}
static void TXT_InputBoxSizeCalc(TXT_UNCAST_ARG(inputbox))
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
// Enough space for the box + cursor
if(inputbox->drawsize)
inputbox->widget.w = inputbox->drawsize + 1;
else
inputbox->widget.w = inputbox->size + 1;
inputbox->widget.h = 1;
}
static void TXT_InputBoxDrawer(TXT_UNCAST_ARG(inputbox))
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
int focused;
int i;
int chars;
int w;
focused = inputbox->widget.focused;
w = inputbox->widget.w;
// Select the background color based on whether we are currently
// editing, and if not, whether the widget is focused.
if (inputbox->editing && focused)
{
TXT_BGColor(TXT_COLOR_BLACK, 0);
}
else
{
TXT_SetWidgetBG(inputbox);
}
if (!inputbox->editing)
{
// If not editing, use the current value from inputbox->value.
SetBufferFromValue(inputbox);
}
// If string size exceeds the widget's width, show only the end.
if (TXT_UTF8_Strlen(inputbox->buffer) > w - 1)
{
TXT_DrawCodePageString("\xae");
TXT_DrawString(
TXT_UTF8_SkipChars(inputbox->buffer,
TXT_UTF8_Strlen(inputbox->buffer) - w + 2));
chars = w - 1;
}
else
{
TXT_DrawString(inputbox->buffer);
chars = TXT_UTF8_Strlen(inputbox->buffer);
}
if (chars < w && inputbox->editing && focused)
{
TXT_BGColor(TXT_COLOR_BLACK, 1);
TXT_DrawString("_");
++chars;
}
for (i=chars; i < w; ++i)
{
TXT_DrawString(" ");
}
}
static void TXT_InputBoxDestructor(TXT_UNCAST_ARG(inputbox))
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
StopEditing(inputbox);
free(inputbox->buffer);
}
static void Backspace(txt_inputbox_t *inputbox)
{
unsigned int len;
char *p;
len = TXT_UTF8_Strlen(inputbox->buffer);
if (len > 0)
{
p = TXT_UTF8_SkipChars(inputbox->buffer, len - 1);
*p = '\0';
}
}
static void AddCharacter(txt_inputbox_t *inputbox, int key)
{
char *end, *p;
if (TXT_UTF8_Strlen(inputbox->buffer) < inputbox->size)
{
// Add character to the buffer
end = inputbox->buffer + strlen(inputbox->buffer);
p = TXT_EncodeUTF8(end, key);
*p = '\0';
}
}
static int TXT_InputBoxKeyPress(TXT_UNCAST_ARG(inputbox), int key)
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
unsigned int c;
if (!inputbox->editing)
{
if (key == KEY_ENTER)
{
StartEditing(inputbox);
return 1;
}
// Backspace or delete erases the contents of the box.
if ((key == KEY_DEL || key == KEY_BACKSPACE)
&& inputbox->widget.widget_class == &txt_inputbox_class)
{
free(*((char **)inputbox->value));
*((char **) inputbox->value) = strdup("");
}
return 0;
}
if (key == KEY_ENTER)
{
FinishEditing(inputbox);
}
if (key == KEY_ESCAPE)
{
StopEditing(inputbox);
}
if (key == KEY_BACKSPACE)
{
Backspace(inputbox);
}
c = TXT_KEY_TO_UNICODE(key);
// Add character to the buffer, but only if it's a printable character
// that we can represent on the screen.
if (isprint(c)
|| (c >= 128 && TXT_UnicodeCharacter(c) >= 0))
{
AddCharacter(inputbox, c);
}
return 1;
}
static void TXT_InputBoxMousePress(TXT_UNCAST_ARG(inputbox),
int x, int y, int b)
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
if (b == TXT_MOUSE_LEFT)
{
// Make mouse clicks start editing the box
if (!inputbox->editing)
{
// Send a simulated keypress to start editing
TXT_WidgetKeyPress(inputbox, KEY_ENTER);
}
}
}
static void TXT_InputBoxFocused(TXT_UNCAST_ARG(inputbox), int focused)
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
// Stop editing when we lose focus.
if (inputbox->editing && !focused)
{
FinishEditing(inputbox);
}
}
txt_widget_class_t txt_inputbox_class =
{
TXT_AlwaysSelectable,
TXT_InputBoxSizeCalc,
TXT_InputBoxDrawer,
TXT_InputBoxKeyPress,
TXT_InputBoxDestructor,
TXT_InputBoxMousePress,
NULL,
TXT_InputBoxFocused,
};
txt_widget_class_t txt_int_inputbox_class =
{
TXT_AlwaysSelectable,
TXT_InputBoxSizeCalc,
TXT_InputBoxDrawer,
TXT_InputBoxKeyPress,
TXT_InputBoxDestructor,
TXT_InputBoxMousePress,
NULL,
TXT_InputBoxFocused,
};
static txt_inputbox_t *NewInputBox(txt_widget_class_t *widget_class,
void *value, int size)
{
txt_inputbox_t *inputbox;
inputbox = malloc(sizeof(txt_inputbox_t));
TXT_InitWidget(inputbox, widget_class);
inputbox->value = value;
inputbox->size = size;
// 'size' is the maximum number of characters that can be entered,
// but for a UTF-8 string, each character can take up to four
// characters.
inputbox->buffer_len = size * 4 + 1;
inputbox->drawsize = 0;
inputbox->buffer = malloc(inputbox->buffer_len);
inputbox->editing = 0;
return inputbox;
}
static txt_inputbox_t* NewInputBoxCustomSize(txt_widget_class_t* widget_class,
void* value, int size, int drawsize)
{
txt_inputbox_t* inputbox;
inputbox = malloc(sizeof(txt_inputbox_t));
TXT_InitWidget(inputbox, widget_class);
inputbox->value = value;
inputbox->size = size;
// 'size' is the maximum number of characters that can be entered,
// but for a UTF-8 string, each character can take up to four
// characters.
inputbox->buffer_len = size * 4 + 1;
inputbox->drawsize = drawsize;
inputbox->buffer = malloc(inputbox->buffer_len);
inputbox->editing = 0;
return inputbox;
}
txt_inputbox_t *TXT_NewInputBox(char **value, int size)
{
return NewInputBox(&txt_inputbox_class, value, size);
}
txt_inputbox_t *TXT_NewIntInputBox(int *value, int size)
{
return NewInputBox(&txt_int_inputbox_class, value, size);
}
txt_inputbox_t* TXT_NewInputBoxCustomSize(char** value, int size, int drawsize)
{
return NewInputBoxCustomSize(&txt_inputbox_class, value, size, drawsize);
}
txt_inputbox_t* TXT_NewIntInputBoxCustomSize(int* value, int size, int drawsize)
{
return NewInputBoxCustomSize(&txt_int_inputbox_class, value, size, drawsize);
}
@@ -0,0 +1,108 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_INPUTBOX_H
#define TXT_INPUTBOX_H
/**
* @file txt_inputbox.h
*
* Input box widget.
*/
/**
* Input box widget.
*
* An input box is a widget that displays a value, which can be
* selected to enter a new value.
*
* Input box widgets can be of an integer or string type.
*/
typedef struct txt_inputbox_s txt_inputbox_t;
#include "txt_widget.h"
struct txt_inputbox_s
{
txt_widget_t widget;
char *buffer;
size_t buffer_len;
unsigned int size;
unsigned int drawsize;
int editing;
void *value;
};
/**
* Create a new input box widget for controlling a string value.
*
* @param value Pointer to a string variable that contains
* a pointer to the current value of the
* input box. The value should be allocated
* dynamically; when the string is changed it
* will be freed and the variable set to point
* to the new string value. String will be in
* UTF-8 format.
* @param size Width of the input box, in characters.
* @return Pointer to the new input box widget.
*/
txt_inputbox_t *TXT_NewInputBox(char **value, int size);
/**
* Create a new input box widget for controlling an integer value.
*
* @param value Pointer to an integer variable containing
* the value of the input box.
* @param size Width of the input box, in characters.
* @return Pointer to the new input box widget.
*/
txt_inputbox_t *TXT_NewIntInputBox(int *value, int size);
/**
* Create a new input box widget for controlling a string value
* with custom draw size.
*
* @param value Pointer to a string variable that contains
* a pointer to the current value of the
* input box. The value should be allocated
* dynamically; when the string is changed it
* will be freed and the variable set to point
* to the new string value. String will be in
* UTF-8 format.
* @param size Maximum number of characters that can be entered.
* @param drawsize Draw width of the input box, in characters.
* @return Pointer to the new input box widget.
*/
txt_inputbox_t* TXT_NewInputBoxCustomSize(char** value, int size, int drawsize);
/**
* Create a new input box widget for controlling an integer value
* with custom draw size.
*
* @param value Pointer to an integer variable containing
* the value of the input box.
* @param size Maximum number of characters that can be entered.
* @param drawsize Draw width of the input box, in characters.
* @return Pointer to the new input box widget.
*/
txt_inputbox_t* TXT_NewIntInputBoxCustomSize(int* value, int size, int drawsize);
#endif /* #ifndef TXT_INPUTBOX_H */
+176
View File
@@ -0,0 +1,176 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Text mode I/O functions, similar to C stdio
//
#include <stdlib.h>
#include <string.h>
#include "txt_io.h"
#include "txt_main.h"
static int cur_x = 0, cur_y = 0;
static txt_color_t fgcolor = TXT_COLOR_GREY;
static txt_color_t bgcolor = TXT_COLOR_BLACK;
static void NewLine(unsigned char *screendata)
{
int i;
unsigned char *p;
cur_x = 0;
++cur_y;
if (cur_y >= TXT_SCREEN_H)
{
// Scroll the screen up
cur_y = TXT_SCREEN_H - 1;
memmove(screendata, screendata + TXT_SCREEN_W * 2,
TXT_SCREEN_W * 2 * (TXT_SCREEN_H -1));
// Clear the bottom line
p = screendata + (TXT_SCREEN_H - 1) * 2 * TXT_SCREEN_W;
for (i=0; i<TXT_SCREEN_W; ++i)
{
*p++ = ' ';
*p++ = fgcolor | (bgcolor << 4);
}
}
}
static void PutSymbol(unsigned char *screendata, int c)
{
unsigned char *p;
p = screendata + cur_y * TXT_SCREEN_W * 2 + cur_x * 2;
// Add a new character to the buffer
p[0] = c;
p[1] = fgcolor | (bgcolor << 4);
++cur_x;
if (cur_x >= TXT_SCREEN_W)
{
NewLine(screendata);
}
}
// "Blind" version of TXT_PutChar() below which doesn't do any interpretation
// of control signals. Just write a particular symbol to the screen buffer.
void TXT_PutSymbol(int c)
{
PutSymbol(TXT_GetScreenData(), c);
}
static void PutChar(unsigned char *screendata, int c)
{
switch (c)
{
case '\n':
NewLine(screendata);
break;
case '\b':
// backspace
--cur_x;
if (cur_x < 0)
cur_x = 0;
break;
default:
PutSymbol(screendata, c);
break;
}
}
void TXT_PutChar(int c)
{
PutChar(TXT_GetScreenData(), c);
}
void TXT_Puts(const char *s)
{
unsigned char *screen;
const char *p;
screen = TXT_GetScreenData();
for (p=s; *p != '\0'; ++p)
{
PutChar(screen, *p);
}
PutChar(screen, '\n');
}
void TXT_GotoXY(int x, int y)
{
cur_x = x;
cur_y = y;
}
void TXT_GetXY(int *x, int *y)
{
*x = cur_x;
*y = cur_y;
}
void TXT_FGColor(txt_color_t color)
{
fgcolor = color;
}
void TXT_BGColor(int color, int blinking)
{
bgcolor = color;
if (blinking)
bgcolor |= TXT_COLOR_BLINKING;
}
void TXT_SaveColors(txt_saved_colors_t *save)
{
save->bgcolor = bgcolor;
save->fgcolor = fgcolor;
}
void TXT_RestoreColors(txt_saved_colors_t *save)
{
bgcolor = save->bgcolor;
fgcolor = save->fgcolor;
}
void TXT_ClearScreen(void)
{
unsigned char *screen;
int i;
screen = TXT_GetScreenData();
for (i=0; i<TXT_SCREEN_W * TXT_SCREEN_H; ++i)
{
screen[i * 2] = ' ';
screen[i * 2 + 1] = (bgcolor << 4) | fgcolor;
}
cur_x = 0;
cur_y = 0;
}
@@ -0,0 +1,41 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Text mode emulation in SDL
//
#ifndef TXT_IO_H
#define TXT_IO_H
#include "txt_main.h"
typedef struct
{
int bgcolor;
int fgcolor;
} txt_saved_colors_t;
void TXT_PutSymbol(int c);
void TXT_PutChar(int c);
void TXT_Puts(const char *s);
void TXT_GotoXY(int x, int y);
void TXT_GetXY(int *x, int *y);
void TXT_FGColor(txt_color_t color);
void TXT_BGColor(int color, int blinking);
void TXT_SaveColors(txt_saved_colors_t *save);
void TXT_RestoreColors(txt_saved_colors_t *save);
void TXT_ClearScreen(void);
#endif /* #ifndef TXT_IO_H */
@@ -0,0 +1,231 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "txt_label.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
static void TXT_LabelSizeCalc(TXT_UNCAST_ARG(label))
{
TXT_CAST_ARG(txt_label_t, label);
label->widget.w = label->w;
label->widget.h = label->h;
}
static void TXT_LabelDrawer(TXT_UNCAST_ARG(label))
{
TXT_CAST_ARG(txt_label_t, label);
unsigned int x, y;
int origin_x, origin_y;
unsigned int align_indent = 0;
unsigned int w, sw;
w = label->widget.w;
if (label->bgcolor >= 0)
{
TXT_BGColor(label->bgcolor, 0);
}
if (label->fgcolor >= 0)
{
TXT_FGColor(label->fgcolor);
}
TXT_GetXY(&origin_x, &origin_y);
for (y=0; y<label->h; ++y)
{
// Calculate the amount to indent this line due to the align
// setting
sw = TXT_UTF8_Strlen(label->lines[y]);
switch (label->widget.align)
{
case TXT_HORIZ_LEFT:
align_indent = 0;
break;
case TXT_HORIZ_CENTER:
align_indent = (label->w - sw) / 2;
break;
case TXT_HORIZ_RIGHT:
align_indent = label->w - sw;
break;
}
// Draw this line
if (label->customlabel == 1)
TXT_GotoXY(origin_x + 1, origin_y + y);
else
TXT_GotoXY(origin_x, origin_y + y);
// Gap at the start
for (x=0; x<align_indent; ++x)
{
TXT_DrawString(" ");
}
// The string itself
TXT_DrawString(label->lines[y]);
x += sw;
// Gap at the end
for (; x<w; ++x)
{
TXT_DrawString(" ");
}
}
}
static void TXT_LabelDestructor(TXT_UNCAST_ARG(label))
{
TXT_CAST_ARG(txt_label_t, label);
free(label->label);
free(label->lines);
}
txt_widget_class_t txt_label_class =
{
TXT_NeverSelectable,
TXT_LabelSizeCalc,
TXT_LabelDrawer,
NULL,
TXT_LabelDestructor,
NULL,
NULL,
};
void TXT_SetLabel(txt_label_t *label, const char *value)
{
char *p;
unsigned int y;
// Free back the old label
free(label->label);
free(label->lines);
// Set the new value
label->label = strdup(value);
// Work out how many lines in this label
label->h = 1;
for (p = label->label; *p != '\0'; ++p)
{
if (*p == '\n')
{
++label->h;
}
}
// Split into lines
label->lines = malloc(sizeof(char *) * label->h);
label->lines[0] = label->label;
y = 1;
for (p = label->label; *p != '\0'; ++p)
{
if (*p == '\n')
{
label->lines[y] = p + 1;
*p = '\0';
++y;
}
}
label->w = 0;
for (y=0; y<label->h; ++y)
{
unsigned int line_len;
line_len = TXT_UTF8_Strlen(label->lines[y]);
if (line_len > label->w)
label->w = line_len;
}
}
txt_label_t* TXT_NewSpecialLabel(const char* text)
{
txt_label_t* label;
label = malloc(sizeof(txt_label_t));
TXT_InitWidget(label, &txt_label_class);
label->label = NULL;
label->lines = NULL;
// Default colors
label->bgcolor = -1;
label->fgcolor = -1;
label->customlabel = 1;
TXT_SetLabel(label, text);
return label;
}
txt_label_t *TXT_NewLabel(const char *text)
{
txt_label_t *label;
label = malloc(sizeof(txt_label_t));
TXT_InitWidget(label, &txt_label_class);
label->label = NULL;
label->lines = NULL;
// Default colors
label->bgcolor = -1;
label->fgcolor = -1;
label->customlabel = 0;
TXT_SetLabel(label, text);
return label;
}
void TXT_SetFGColor(txt_label_t *label, txt_color_t color)
{
label->fgcolor = color;
}
void TXT_SetBGColor(txt_label_t *label, txt_color_t color)
{
label->bgcolor = color;
}
@@ -0,0 +1,93 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_LABEL_H
#define TXT_LABEL_H
/**
* @file txt_label.h
*
* Text label widget.
*/
/**
* Label widget.
*
* A label widget does nothing except show a text label.
*/
typedef struct txt_label_s txt_label_t;
#include "txt_main.h"
#include "txt_widget.h"
struct txt_label_s
{
txt_widget_t widget;
char *label;
char **lines;
unsigned int w, h;
int fgcolor;
int bgcolor;
int customlabel;
};
/**
* Create a new label widget.
*
* @param label String to display in the widget (UTF-8 format).
* @return Pointer to the new label widget.
*/
txt_label_t *TXT_NewLabel(const char *label);
/**
* Create a new label widget at position +1 on x axis.
*
* @param label String to display in the widget (UTF-8 format).
* @return Pointer to the new label widget.
*/
txt_label_t* TXT_NewSpecialLabel(const char* label);
/**
* Set the string displayed in a label widget.
*
* @param label The widget.
* @param value The string to display (UTF-8 format).
*/
void TXT_SetLabel(txt_label_t *label, const char *value);
/**
* Set the background color of a label widget.
*
* @param label The widget.
* @param color The background color to use.
*/
void TXT_SetBGColor(txt_label_t *label, txt_color_t color);
/**
* Set the foreground color of a label widget.
*
* @param label The widget.
* @param color The foreground color to use.
*/
void TXT_SetFGColor(txt_label_t *label, txt_color_t color);
#endif /* #ifndef TXT_LABEL_H */
@@ -0,0 +1,204 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Base interface that abstracts the text mode screen.
//
#ifndef TXT_MAIN_H
#define TXT_MAIN_H
// For the moment, txt_sdl.c is the only implementation of the base
// text mode screen API:
#include "txt_sdl.h"
// textscreen key values:
// Key values are difficult because we have to support multiple conflicting
// address spaces.
// First, Doom's key constants use 0-127 as ASCII and extra values from
// 128-255 to represent special keys. Second, mouse buttons are represented
// as buttons. Finally, we want to be able to support Unicode.
//
// So we define different ranges:
// 0-255: Doom key constants, including ASCII.
// 256-511: Mouse buttons and other reserved.
// >=512: Unicode values greater than 127 are offset up into this range.
// Special keypress values that correspond to mouse button clicks
#define TXT_MOUSE_BASE 256
#define TXT_MOUSE_LEFT (TXT_MOUSE_BASE + 0)
#define TXT_MOUSE_RIGHT (TXT_MOUSE_BASE + 1)
#define TXT_MOUSE_MIDDLE (TXT_MOUSE_BASE + 2)
#define TXT_MOUSE_SCROLLUP (TXT_MOUSE_BASE + 3)
#define TXT_MOUSE_SCROLLDOWN (TXT_MOUSE_BASE + 4)
#define TXT_MAX_MOUSE_BUTTONS 16
#define TXT_KEY_TO_MOUSE_BUTTON(x) \
( (x) >= TXT_MOUSE_BASE \
&& (x) < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS ? \
(x) - TXT_MOUSE_BASE : -1 )
// Unicode offset. Unicode values from 128 onwards are offset up into
// this range, so TXT_UNICODE_BASE = Unicode character #128, and so on.
#define TXT_UNICODE_BASE 512
// Convert a key value to a Unicode character:
#define TXT_KEY_TO_UNICODE(x) \
( (x) < 128 ? (x) : \
(x) >= TXT_UNICODE_BASE ? ((x) - TXT_UNICODE_BASE + 128) : 0 )
// Convert a Unicode character to a key value:
#define TXT_UNICODE_TO_KEY(u) \
( (u) < 128 ? (u) : ((u) - 128 + TXT_UNICODE_BASE) )
// Screen size
#define TXT_SCREEN_W 80
#define TXT_SCREEN_H 25
#define TXT_COLOR_BLINKING (1 << 3)
typedef enum
{
TXT_COLOR_BLACK,
TXT_COLOR_BLUE,
TXT_COLOR_GREEN,
TXT_COLOR_CYAN,
TXT_COLOR_RED,
TXT_COLOR_MAGENTA,
TXT_COLOR_BROWN,
TXT_COLOR_GREY,
TXT_COLOR_DARK_GREY,
TXT_COLOR_BRIGHT_BLUE,
TXT_COLOR_BRIGHT_GREEN,
TXT_COLOR_BRIGHT_CYAN,
TXT_COLOR_BRIGHT_RED,
TXT_COLOR_BRIGHT_MAGENTA,
TXT_COLOR_YELLOW,
TXT_COLOR_BRIGHT_WHITE,
} txt_color_t;
// Modifier keys.
typedef enum
{
TXT_MOD_SHIFT,
TXT_MOD_CTRL,
TXT_MOD_ALT,
TXT_NUM_MODIFIERS
} txt_modifier_t;
// Due to the way the SDL API works, we provide different ways of configuring
// how we read input events, each of which is useful in different scenarios.
typedef enum
{
// "Localized" output that takes software keyboard layout into account,
// but key shifting has no effect.
TXT_INPUT_NORMAL,
// "Raw" input; the keys correspond to physical keyboard layout and
// software keyboard layout has no effect.
TXT_INPUT_RAW,
// Used for full text input. Events are fully shifted and localized.
// However, not all keyboard keys will generate input.
// Setting this mode may activate the on-screen keyboard, depending on
// device and OS.
TXT_INPUT_TEXT,
} txt_input_mode_t;
#ifdef __GNUC__
#define PRINTF_ATTR(fmt, first) __attribute__((format(printf, fmt, first)))
#else // __GNUC__
#define PRINTF_ATTR(fmt, first)
#endif // __GNUC__
// Initialize the screen
// Returns 1 if successful, 0 if failed.
int TXT_Init(void);
// Shut down text mode emulation
void TXT_Shutdown(void);
// Get a pointer to the buffer containing the raw screen data.
unsigned char *TXT_GetScreenData(void);
// Update an area of the screen
void TXT_UpdateScreenArea(int x, int y, int w, int h);
// Update the whole screen
void TXT_UpdateScreen(void);
// Set the RGB value for a particular entry in the color palette:
void TXT_SetColor(txt_color_t color, int r, int g, int b);
// Read a character from the keyboard
int TXT_GetChar(void);
// Given a Unicode character, get a character that can be used to represent
// it on the code page being displayed on the screen. If the character cannot
// be represented, this returns -1.
int TXT_UnicodeCharacter(unsigned int c);
// Read the current state of modifier keys that are held down.
int TXT_GetModifierState(txt_modifier_t mod);
// Provides a short description of a key code, placing into the provided
// buffer. Note that the key is assumed to represent a physical key on the
// keyboard (like that returned by TXT_INPUT_RAW), and the resulting string
// takes keyboard layout into consideration. For example,
// TXT_GetKeyDescription('q') on a French keyboard returns "A".
// The contents of the filled buffer will be in UTF-8 format, but will never
// contain characters which can't be shown on the screen.
void TXT_GetKeyDescription(int key, char *buf, size_t buf_len);
// Retrieve the current position of the mouse
void TXT_GetMousePosition(int *x, int *y);
// Sleep until an event is received or the screen needs updating
// Optional timeout in ms (timeout == 0 : sleep forever)
void TXT_Sleep(int timeout);
// Change mode for text input.
void TXT_SetInputMode(txt_input_mode_t mode);
// Set the window title of the window containing the text mode screen
void TXT_SetWindowTitle(const char *title);
// Safe string copy.
void TXT_StringCopy(char *dest, const char *src, size_t dest_len);
// Safe string concatenate.
void TXT_StringConcat(char *dest, const char *src, size_t dest_len);
// Safe version of vsnprintf().
int TXT_vsnprintf(char *buf, size_t buf_len, const char *s, va_list args);
// Safe version of snprintf().
int TXT_snprintf(char *buf, size_t buf_len, const char *s, ...) PRINTF_ATTR(3, 4);
// Set fullscreenmode
void TXT_Fullscreen(int fullscreen);
#endif /* #ifndef TXT_MAIN_H */
@@ -0,0 +1,147 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_radiobutton.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
static void TXT_RadioButtonSizeCalc(TXT_UNCAST_ARG(radiobutton))
{
TXT_CAST_ARG(txt_radiobutton_t, radiobutton);
// Minimum width is the string length + right-side spaces for padding
radiobutton->widget.w = TXT_UTF8_Strlen(radiobutton->label) + 5;
radiobutton->widget.h = 1;
}
static void TXT_RadioButtonDrawer(TXT_UNCAST_ARG(radiobutton))
{
TXT_CAST_ARG(txt_radiobutton_t, radiobutton);
txt_saved_colors_t colors;
int i;
int w;
w = radiobutton->widget.w;
TXT_SaveColors(&colors);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString("(");
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
if (*radiobutton->variable == radiobutton->value)
{
TXT_DrawCodePageString("\x07");
}
else
{
TXT_DrawString(" ");
}
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString(") ");
TXT_RestoreColors(&colors);
TXT_SetWidgetBG(radiobutton);
TXT_DrawString(radiobutton->label);
for (i=TXT_UTF8_Strlen(radiobutton->label); i < w-5; ++i)
{
TXT_DrawString(" ");
}
}
static void TXT_RadioButtonDestructor(TXT_UNCAST_ARG(radiobutton))
{
TXT_CAST_ARG(txt_radiobutton_t, radiobutton);
free(radiobutton->label);
}
static int TXT_RadioButtonKeyPress(TXT_UNCAST_ARG(radiobutton), int key)
{
TXT_CAST_ARG(txt_radiobutton_t, radiobutton);
if (key == KEY_ENTER || key == ' ')
{
if (*radiobutton->variable != radiobutton->value)
{
*radiobutton->variable = radiobutton->value;
TXT_EmitSignal(radiobutton, "selected");
}
return 1;
}
return 0;
}
static void TXT_RadioButtonMousePress(TXT_UNCAST_ARG(radiobutton),
int x, int y, int b)
{
TXT_CAST_ARG(txt_radiobutton_t, radiobutton);
if (b == TXT_MOUSE_LEFT)
{
// Equivalent to pressing enter
TXT_RadioButtonKeyPress(radiobutton, KEY_ENTER);
}
}
txt_widget_class_t txt_radiobutton_class =
{
TXT_AlwaysSelectable,
TXT_RadioButtonSizeCalc,
TXT_RadioButtonDrawer,
TXT_RadioButtonKeyPress,
TXT_RadioButtonDestructor,
TXT_RadioButtonMousePress,
NULL,
};
txt_radiobutton_t *TXT_NewRadioButton(const char *label, int *variable, int value)
{
txt_radiobutton_t *radiobutton;
radiobutton = malloc(sizeof(txt_radiobutton_t));
TXT_InitWidget(radiobutton, &txt_radiobutton_class);
radiobutton->label = strdup(label);
radiobutton->variable = variable;
radiobutton->value = value;
return radiobutton;
}
void TXT_SetRadioButtonLabel(txt_radiobutton_t *radiobutton, const char *value)
{
free(radiobutton->label);
radiobutton->label = strdup(value);
}
@@ -0,0 +1,79 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_RADIOBUTTON_H
#define TXT_RADIOBUTTON_H
/**
* @file txt_radiobutton.h
*
* Radio button widget.
*/
/**
* A radio button widget.
*
* Radio buttons are typically used in groups, to allow a value to be
* selected from a range of options. Each radio button corresponds
* to a particular option that may be selected. A radio button
* has an indicator to indicate whether it is the currently-selected
* value, and a text label.
*
* Internally, a radio button tracks an integer variable that may take
* a range of different values. Each radio button has a particular
* value associated with it; if the variable is equal to that value,
* the radio button appears selected. If a radio button is pressed
* by the user through the GUI, the variable is set to its value.
*
* When a radio button is selected, the "selected" signal is emitted.
*/
typedef struct txt_radiobutton_s txt_radiobutton_t;
#include "txt_widget.h"
struct txt_radiobutton_s
{
txt_widget_t widget;
char *label;
int *variable;
int value;
};
/**
* Create a new radio button widget.
*
* @param label The label to display next to the radio button
* (UTF-8 format).
* @param variable Pointer to the variable tracking whether this
* radio button is selected.
* @param value If the variable is equal to this value, the
* radio button appears selected.
* @return Pointer to the new radio button widget.
*/
txt_radiobutton_t *TXT_NewRadioButton(const char *label, int *variable, int value);
/**
* Set the label on a radio button.
*
* @param radiobutton The radio button.
* @param value The new label (UTF-8 format).
*/
void TXT_SetRadioButtonLabel(txt_radiobutton_t *radiobutton, const char *value);
#endif /* #ifndef TXT_RADIOBUTTON_H */
@@ -0,0 +1,586 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "txt_scrollpane.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_table.h"
#include "doomkeys.h"
#define SCROLLBAR_VERTICAL (1 << 0)
#define SCROLLBAR_HORIZONTAL (1 << 1)
static int FullWidth(txt_scrollpane_t *scrollpane)
{
if (scrollpane->child != NULL)
{
return scrollpane->child->w;
}
else
{
return 0;
}
}
static int FullHeight(txt_scrollpane_t *scrollpane)
{
if (scrollpane->child != NULL)
{
return scrollpane->child->h;
}
else
{
return 0;
}
}
// Calculate which scroll bars the pane needs.
static int NeedsScrollbars(txt_scrollpane_t *scrollpane)
{
int result;
result = 0;
if (FullWidth(scrollpane) > scrollpane->w)
{
result |= SCROLLBAR_HORIZONTAL;
}
if (FullHeight(scrollpane) > scrollpane->h)
{
result |= SCROLLBAR_VERTICAL;
}
return result;
}
// If a scrollbar isn't needed, the scroll position is reset.
static void SanityCheckScrollbars(txt_scrollpane_t *scrollpane)
{
int scrollbars;
int max_x, max_y;
scrollbars = NeedsScrollbars(scrollpane);
if ((scrollbars & SCROLLBAR_HORIZONTAL) == 0)
{
scrollpane->x = 0;
}
if ((scrollbars & SCROLLBAR_VERTICAL) == 0)
{
scrollpane->y = 0;
}
max_x = FullWidth(scrollpane) - scrollpane->w;
max_y = FullHeight(scrollpane) - scrollpane->h;
if (scrollpane->x < 0)
{
scrollpane->x = 0;
}
else if (scrollpane->x > max_x)
{
scrollpane->x = max_x;
}
if (scrollpane->y < 0)
{
scrollpane->y = 0;
}
else if (scrollpane->y > max_y)
{
scrollpane->y = max_y;
}
}
static void TXT_ScrollPaneSizeCalc(TXT_UNCAST_ARG(scrollpane))
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
int scrollbars;
if (scrollpane->child != NULL)
{
TXT_CalcWidgetSize(scrollpane->child);
}
// Expand as necessary (to ensure that no scrollbars are needed)?
if (scrollpane->expand_w)
{
scrollpane->w = FullWidth(scrollpane);
}
if (scrollpane->expand_h)
{
scrollpane->h = FullHeight(scrollpane);
}
scrollpane->widget.w = scrollpane->w;
scrollpane->widget.h = scrollpane->h;
// If we have scroll bars, we need to expand slightly to
// accomodate them. Eg. if we have a vertical scrollbar, we
// need to be an extra character wide.
scrollbars = NeedsScrollbars(scrollpane);
if (scrollbars & SCROLLBAR_HORIZONTAL)
{
++scrollpane->widget.h;
}
if (scrollbars & SCROLLBAR_VERTICAL)
{
++scrollpane->widget.w;
}
if (scrollpane->child != NULL)
{
if (scrollpane->child->w < scrollpane->w)
{
scrollpane->child->w = scrollpane->w;
}
if (scrollpane->child->h < scrollpane->h)
{
scrollpane->child->h = scrollpane->h;
}
}
}
static void TXT_ScrollPaneDrawer(TXT_UNCAST_ARG(scrollpane))
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
int x1, y1, x2, y2;
int scrollbars;
// We set a clipping area of the scroll pane.
x1 = scrollpane->widget.x,
y1 = scrollpane->widget.y,
x2 = x1 + scrollpane->w,
y2 = y1 + scrollpane->h;
scrollbars = NeedsScrollbars(scrollpane);
if (scrollbars & SCROLLBAR_HORIZONTAL)
{
TXT_DrawHorizScrollbar(x1,
y1 + scrollpane->h,
scrollpane->w,
scrollpane->x,
FullWidth(scrollpane) - scrollpane->w);
}
if (scrollbars & SCROLLBAR_VERTICAL)
{
TXT_DrawVertScrollbar(x1 + scrollpane->w,
y1,
scrollpane->h,
scrollpane->y,
FullHeight(scrollpane) - scrollpane->h);
}
TXT_PushClipArea(x1, x2, y1, y2);
// Draw the child widget
if (scrollpane->child != NULL)
{
TXT_DrawWidget(scrollpane->child);
}
// Restore old clipping area.
TXT_PopClipArea();
}
static void TXT_ScrollPaneDestructor(TXT_UNCAST_ARG(scrollpane))
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
if (scrollpane->child != NULL)
{
TXT_DestroyWidget(scrollpane->child);
}
}
static void TXT_ScrollPaneFocused(TXT_UNCAST_ARG(scrollpane), int focused)
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
// Whether the child is focused depends only on whether the scroll pane
// itself is focused. Pass through focus to the child.
if (scrollpane->child != NULL)
{
TXT_SetWidgetFocus(scrollpane->child, focused);
}
}
// Hack for tables - when browsing a table inside a scroll pane,
// automatically scroll the window to show the newly-selected
// item.
static void ShowSelectedWidget(txt_scrollpane_t *scrollpane)
{
txt_widget_t *selected;
selected = TXT_GetSelectedWidget(scrollpane->child);
// Scroll up or down?
if (selected->y <= scrollpane->widget.y)
{
scrollpane->y -= scrollpane->widget.y - selected->y;
}
else if ((signed) (selected->y + selected->h) >
(signed) (scrollpane->widget.y + scrollpane->h))
{
scrollpane->y += (selected->y + selected->h)
- (scrollpane->widget.y + scrollpane->h);
}
// Scroll left or right?
if (selected->x <= scrollpane->widget.x)
{
scrollpane->x -= scrollpane->widget.x - selected->x;
}
else if ((signed) (selected->x + selected->w) >
(signed) (scrollpane->widget.x + scrollpane->w))
{
scrollpane->x += (selected->x + selected->w)
- (scrollpane->widget.x + scrollpane->w);
}
}
// Another hack for tables - when scrolling in 'pages', the normal key press
// event does not provide children with enough information to know how far
// to move their selection to reach a new page. This function does so.
// Note that it *only* affects scrolling in pages, not with arrows!
// A side-effect of this, rather than 'pulling' the selection to fit within
// the new page, is that we will jump straight over ranges of unselectable
// items longer than a page, but that is also true of arrow-key scrolling.
// The other unfortunate effect of doing things this way is that page keys
// have no effect on tables _not_ in scrollpanes: not even home/end.
static int PageSelectedWidget(txt_scrollpane_t *scrollpane, int key)
{
int pagex = 0; // No page left/right yet, but some keyboards have them
int pagey = 0;
// Subtract one from the absolute page distance as this is slightly more
// intuitive: a page down first jumps to the bottom of the current page,
// then proceeds to scroll onwards.
switch (key)
{
case KEY_PGUP:
pagey = 1 - scrollpane->h;
break;
case KEY_PGDN:
pagey = scrollpane->h - 1;
break;
default: // We shouldn't even be in this function
return 0;
}
if (scrollpane->child->widget_class == &txt_table_class)
{
return TXT_PageTable(scrollpane->child, pagex, pagey);
}
return 0;
}
// Interpret arrow key presses as scroll commands
static int InterpretScrollKey(txt_scrollpane_t *scrollpane, int key)
{
int maxy;
switch (key)
{
case KEY_UPARROW:
if (scrollpane->y > 0)
{
--scrollpane->y;
return 1;
}
break;
case KEY_DOWNARROW:
if (scrollpane->y < FullHeight(scrollpane) - scrollpane->h)
{
++scrollpane->y;
return 1;
}
break;
case KEY_LEFTARROW:
if (scrollpane->x > 0)
{
--scrollpane->x;
return 1;
}
break;
case KEY_RIGHTARROW:
if (scrollpane->x < FullWidth(scrollpane) - scrollpane->w)
{
++scrollpane->x;
return 1;
}
break;
case KEY_PGUP:
if (scrollpane->y > 0)
{
scrollpane->y -= scrollpane->h;
if (scrollpane->y < 0)
{
scrollpane->y = 0;
}
return 1;
}
break;
case KEY_PGDN:
maxy = FullHeight(scrollpane) - scrollpane->h;
if (scrollpane->y < maxy)
{
scrollpane->y += scrollpane->h;
if (scrollpane->y > maxy)
{
scrollpane->y = maxy;
}
return 1;
}
break;
default:
break;
}
return 0;
}
static int TXT_ScrollPaneKeyPress(TXT_UNCAST_ARG(scrollpane), int key)
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
int result;
result = 0;
if (scrollpane->child != NULL)
{
result = TXT_WidgetKeyPress(scrollpane->child, key);
// Gross hack - if we're scrolling in a menu with the keyboard,
// automatically move the scroll pane to show the new
// selected item.
if ((key == KEY_UPARROW || key == KEY_DOWNARROW
|| key == KEY_LEFTARROW || key == KEY_RIGHTARROW
|| key == KEY_PGUP || key == KEY_PGDN
|| key == KEY_TAB)
&& scrollpane->child->widget_class == &txt_table_class)
{
if (PageSelectedWidget(scrollpane, key))
{
result = 1;
}
ShowSelectedWidget(scrollpane);
}
// If the child widget didn't use the keypress, we can see
// if it can be interpreted as a scrolling command.
if (result == 0)
{
result = InterpretScrollKey(scrollpane, key);
}
}
return result;
}
static void TXT_ScrollPaneMousePress(TXT_UNCAST_ARG(scrollpane),
int x, int y, int b)
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
int scrollbars;
int rel_x, rel_y;
scrollbars = NeedsScrollbars(scrollpane);
if (b == TXT_MOUSE_SCROLLUP)
{
if (scrollbars & SCROLLBAR_VERTICAL)
{
scrollpane->y -= 3;
}
else if (scrollbars & SCROLLBAR_HORIZONTAL)
{
scrollpane->x -= 3;
}
return;
}
else if (b == TXT_MOUSE_SCROLLDOWN)
{
if (scrollbars & SCROLLBAR_VERTICAL)
{
scrollpane->y += 3;
}
else if (scrollbars & SCROLLBAR_HORIZONTAL)
{
scrollpane->x += 3;
}
return;
}
rel_x = x - scrollpane->widget.x;
rel_y = y - scrollpane->widget.y;
// Click on the horizontal scrollbar?
if ((scrollbars & SCROLLBAR_HORIZONTAL) && rel_y == scrollpane->h)
{
if (rel_x == 0)
{
--scrollpane->x;
}
else if (rel_x == scrollpane->w - 1)
{
++scrollpane->x;
}
else
{
int range = FullWidth(scrollpane) - scrollpane->w;
int bar_max = scrollpane->w - 3;
scrollpane->x = ((rel_x - 1) * range + bar_max - 1) / bar_max;
}
return;
}
// Click on the vertical scrollbar?
if ((scrollbars & SCROLLBAR_VERTICAL) && rel_x == scrollpane->w)
{
if (rel_y == 0)
{
--scrollpane->y;
}
else if (rel_y == scrollpane->h - 1)
{
++scrollpane->y;
}
else
{
int range = FullHeight(scrollpane) - scrollpane->h;
int bar_max = scrollpane->h - 3;
scrollpane->y = ((rel_y - 1) * range + bar_max - 1) / bar_max;
}
return;
}
if (scrollpane->child != NULL)
{
TXT_WidgetMousePress(scrollpane->child, x, y, b);
}
}
static void TXT_ScrollPaneLayout(TXT_UNCAST_ARG(scrollpane))
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
SanityCheckScrollbars(scrollpane);
// The child widget takes the same position as the scroll pane
// itself, but is offset by the scroll position.
if (scrollpane->child != NULL)
{
scrollpane->child->x = scrollpane->widget.x - scrollpane->x;
scrollpane->child->y = scrollpane->widget.y - scrollpane->y;
TXT_LayoutWidget(scrollpane->child);
}
}
static int TXT_ScrollPaneSelectable(TXT_UNCAST_ARG(scrollpane))
{
TXT_CAST_ARG(txt_scrollpane_t, scrollpane);
// If scroll bars are displayed, the scroll pane must be selectable
// so that we can use the arrow keys to scroll around.
if (NeedsScrollbars(scrollpane))
{
return 1;
}
// Otherwise, whether this is selectable depends on the child widget.
return TXT_SelectableWidget(scrollpane->child);
}
txt_widget_class_t txt_scrollpane_class =
{
TXT_ScrollPaneSelectable,
TXT_ScrollPaneSizeCalc,
TXT_ScrollPaneDrawer,
TXT_ScrollPaneKeyPress,
TXT_ScrollPaneDestructor,
TXT_ScrollPaneMousePress,
TXT_ScrollPaneLayout,
TXT_ScrollPaneFocused,
};
txt_scrollpane_t *TXT_NewScrollPane(int w, int h, TXT_UNCAST_ARG(target))
{
TXT_CAST_ARG(txt_widget_t, target);
txt_scrollpane_t *scrollpane;
scrollpane = malloc(sizeof(txt_scrollpane_t));
TXT_InitWidget(scrollpane, &txt_scrollpane_class);
scrollpane->w = w;
scrollpane->h = h;
scrollpane->x = 0;
scrollpane->y = 0;
scrollpane->child = target;
scrollpane->expand_w = w <= 0;
scrollpane->expand_h = h <= 0;
// Set parent pointer for inner widget.
target->parent = &scrollpane->widget;
return scrollpane;
}
@@ -0,0 +1,59 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_SCROLLPANE_H
#define TXT_SCROLLPANE_H
/**
* @file txt_scrollpane.h
*
* Scrollable pane widget.
*/
/**
* Scrollable pane widget.
*
* A scrollable pane widget is a widget that contains another widget
* that is larger than it. Scroll bars appear on the side to allow
* different areas of the contained widget to be seen.
*/
typedef struct txt_scrollpane_s txt_scrollpane_t;
#include "txt_widget.h"
struct txt_scrollpane_s
{
txt_widget_t widget;
int w, h;
int x, y;
int expand_w, expand_h;
txt_widget_t *child;
};
/**
* Create a new scroll pane widget.
*
* @param w Width of the scroll pane, in characters.
* @param h Height of the scroll pane, in lines.
* @param target The target widget that the scroll pane will
* contain.
* @return Pointer to the new scroll pane widget.
*/
txt_scrollpane_t *TXT_NewScrollPane(int w, int h, TXT_UNCAST_ARG(target));
#endif /* #ifndef TXT_SCROLLPANE_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,41 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//
// Text mode emulation in SDL
//
#ifndef TXT_SDL_H
#define TXT_SDL_H
// The textscreen API itself doesn't need SDL; however, SDL needs its
// headers included where main() is defined.
#include "SDL.h"
// Event callback function type: a function of this type can be used
// to intercept events in the textscreen event processing loop.
// Returning 1 will cause the event to be eaten; the textscreen code
// will not see it.
typedef int (*TxtSDLEventCallbackFunc)(SDL_Event *event, void *user_data);
// Set a callback function to call in the SDL event loop. Useful for
// intercepting events. Pass callback=NULL to clear an existing
// callback function.
// user_data is a void pointer to be passed to the callback function.
void TXT_SDL_SetEventCallback(TxtSDLEventCallbackFunc callback, void *user_data);
#endif /* #ifndef TXT_SDL_H */
@@ -0,0 +1,155 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "txt_separator.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
static void TXT_SeparatorSizeCalc(TXT_UNCAST_ARG(separator))
{
TXT_CAST_ARG(txt_separator_t, separator);
if (separator->label != NULL)
{
// Minimum width is the string length + two spaces for padding
separator->widget.w = TXT_UTF8_Strlen(separator->label) + 2;
}
else
{
separator->widget.w = 0;
}
separator->widget.h = 1;
}
static void TXT_SeparatorDrawer(TXT_UNCAST_ARG(separator))
{
TXT_CAST_ARG(txt_separator_t, separator);
int x, y;
int w;
w = separator->widget.w;
TXT_GetXY(&x, &y);
// Draw special separator with custom hight, width and color argument else draw standard separator
// Draw separator. Go back one character and draw two extra
// to overlap the window borders.
if (separator->specialsep == 1)
TXT_DrawSpecialSeparator(x, y, w + separator->w, separator->h, separator->sepcolor, 1);
else
TXT_DrawSeparator(x - 2, y, w + 4, 0, 0);
if (separator->label != NULL)
{
if (separator->specialsep == 1)
{
TXT_GotoXY(x + 1, y);
TXT_FGColor(TXT_COLOR_BRIGHT_GREEN);
TXT_DrawString(separator->label);
}
else
{
TXT_GotoXY(x, y);
TXT_FGColor(TXT_COLOR_BRIGHT_GREEN);
TXT_DrawString(" ");
TXT_DrawString(separator->label);
TXT_DrawString(" ");
}
}
}
static void TXT_SeparatorDestructor(TXT_UNCAST_ARG(separator))
{
TXT_CAST_ARG(txt_separator_t, separator);
free(separator->label);
}
void TXT_SetSeparatorLabel(txt_separator_t *separator, const char *label)
{
free(separator->label);
if (label != NULL)
{
separator->label = strdup(label);
}
else
{
separator->label = NULL;
}
}
txt_widget_class_t txt_separator_class =
{
TXT_NeverSelectable,
TXT_SeparatorSizeCalc,
TXT_SeparatorDrawer,
NULL,
TXT_SeparatorDestructor,
NULL,
NULL,
};
txt_separator_t* TXT_NewSpecialSeparator(const char* label, int w, int h, int sepcolor)
{
txt_separator_t* separator;
separator = malloc(sizeof(txt_separator_t));
separator->sepcolor = sepcolor;
separator->specialsep = 1;
separator->w = w;
separator->h = h;
TXT_InitWidget(separator, &txt_separator_class);
separator->label = NULL;
TXT_SetSeparatorLabel(separator, label);
return separator;
}
txt_separator_t *TXT_NewSeparator(const char *label)
{
txt_separator_t *separator;
separator = malloc(sizeof(txt_separator_t));
separator->specialsep = 0;
TXT_InitWidget(separator, &txt_separator_class);
separator->label = NULL;
TXT_SetSeparatorLabel(separator, label);
return separator;
}
@@ -0,0 +1,83 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_SEPARATOR_H
#define TXT_SEPARATOR_H
/**
* @file txt_separator.h
*
* Horizontal separator widget.
*/
/**
* Horizontal separator.
*
* A horizontal separator appears as a horizontal line divider across
* the length of the window in which it is added. An optional label
* allows the separator to be used as a section divider for grouping
* related controls.
*/
typedef struct txt_separator_s txt_separator_t;
#include "txt_widget.h"
struct txt_separator_s
{
txt_widget_t widget;
char *label;
int specialsep;
int sepcolor;
int w;
int h;
};
extern txt_widget_class_t txt_separator_class;
/**
* Create a new horizontal and vertical separator widget.
*
* @param label Label to display on the separator (UTF-8 format).
* If this is set to NULL, no label is displayed.
* @param w Width of separator
* @param h Hidth of separator
* @param sepcolor Color of separator
* @return The new separator widget.
*/
txt_separator_t* TXT_NewSpecialSeparator(const char* label, int w, int h, int sepcolor);
/**
* Create a new horizontal separator widget.
*
* @param label Label to display on the separator (UTF-8 format).
* If this is set to NULL, no label is displayed.
* @return The new separator widget.
*/
txt_separator_t *TXT_NewSeparator(const char *label);
/**
* Change the label on a separator.
*
* @param separator The separator.
* @param label The new label (UTF-8 format).
*/
void TXT_SetSeparatorLabel(txt_separator_t *separator, const char *label);
#endif /* #ifndef TXT_SEPARATOR_H */
@@ -0,0 +1,424 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "doomkeys.h"
#include "txt_spinctrl.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
// Generate the format string to be used for displaying floats
static void FloatFormatString(float step, char *buf, size_t buf_len)
{
int precision;
precision = (int) ceil(-log(step) / log(10));
if (precision > 0)
{
TXT_snprintf(buf, buf_len, "%%.%if", precision);
}
else
{
TXT_StringCopy(buf, "%.1f", buf_len);
}
}
// Number of characters needed to represent a character
static unsigned int IntWidth(int val)
{
char buf[25];
TXT_snprintf(buf, sizeof(buf), "%i", val);
return strlen(buf);
}
static unsigned int FloatWidth(float val, float step)
{
unsigned int precision;
unsigned int result;
// Calculate the width of the int value
result = IntWidth((int) val);
// Add a decimal part if the precision specifies it
precision = (unsigned int) ceil(-log(step) / log(10));
if (precision > 0)
{
result += precision + 1;
}
return result;
}
// Returns the minimum width of the input box
static unsigned int SpinControlWidth(txt_spincontrol_t *spincontrol)
{
unsigned int minw, maxw;
switch (spincontrol->type)
{
case TXT_SPINCONTROL_FLOAT:
minw = FloatWidth(spincontrol->min.f, spincontrol->step.f);
maxw = FloatWidth(spincontrol->max.f, spincontrol->step.f);
break;
default:
case TXT_SPINCONTROL_INT:
minw = IntWidth(spincontrol->min.i);
maxw = IntWidth(spincontrol->max.i);
break;
}
// Choose the wider of the two values. Add one so that there is always
// space for the cursor when editing.
if (minw > maxw)
{
return minw;
}
else
{
return maxw;
}
}
static void TXT_SpinControlSizeCalc(TXT_UNCAST_ARG(spincontrol))
{
TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
spincontrol->widget.w = SpinControlWidth(spincontrol) + 5;
spincontrol->widget.h = 1;
}
static void SetBuffer(txt_spincontrol_t *spincontrol)
{
char format[25];
switch (spincontrol->type)
{
case TXT_SPINCONTROL_INT:
TXT_snprintf(spincontrol->buffer, spincontrol->buffer_len,
"%i", spincontrol->value->i);
break;
case TXT_SPINCONTROL_FLOAT:
FloatFormatString(spincontrol->step.f, format, sizeof(format));
TXT_snprintf(spincontrol->buffer, spincontrol->buffer_len,
format, spincontrol->value->f);
break;
}
}
static void TXT_SpinControlDrawer(TXT_UNCAST_ARG(spincontrol))
{
TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
unsigned int i;
unsigned int padding;
txt_saved_colors_t colors;
int bw;
int focused;
focused = spincontrol->widget.focused;
TXT_SaveColors(&colors);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawCodePageString("\x1b ");
TXT_RestoreColors(&colors);
// Choose background color
if (focused && spincontrol->editing)
{
TXT_BGColor(TXT_COLOR_BLACK, 0);
}
else
{
TXT_SetWidgetBG(spincontrol);
}
if (!spincontrol->editing)
{
SetBuffer(spincontrol);
}
i = 0;
bw = TXT_UTF8_Strlen(spincontrol->buffer);
padding = spincontrol->widget.w - bw - 4;
while (i < padding)
{
TXT_DrawString(" ");
++i;
}
TXT_DrawString(spincontrol->buffer);
i += bw;
while (i < spincontrol->widget.w - 4)
{
TXT_DrawString(" ");
++i;
}
TXT_RestoreColors(&colors);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawCodePageString(" \x1a");
}
static void TXT_SpinControlDestructor(TXT_UNCAST_ARG(spincontrol))
{
TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
free(spincontrol->buffer);
}
static void AddCharacter(txt_spincontrol_t *spincontrol, int key)
{
if (TXT_UTF8_Strlen(spincontrol->buffer) < SpinControlWidth(spincontrol)
&& strlen(spincontrol->buffer) < spincontrol->buffer_len - 2)
{
spincontrol->buffer[strlen(spincontrol->buffer) + 1] = '\0';
spincontrol->buffer[strlen(spincontrol->buffer)] = key;
}
}
static void Backspace(txt_spincontrol_t *spincontrol)
{
if (TXT_UTF8_Strlen(spincontrol->buffer) > 0)
{
spincontrol->buffer[strlen(spincontrol->buffer) - 1] = '\0';
}
}
static void EnforceLimits(txt_spincontrol_t *spincontrol)
{
switch (spincontrol->type)
{
case TXT_SPINCONTROL_INT:
if (spincontrol->value->i > spincontrol->max.i)
spincontrol->value->i = spincontrol->max.i;
else if (spincontrol->value->i < spincontrol->min.i)
spincontrol->value->i = spincontrol->min.i;
break;
case TXT_SPINCONTROL_FLOAT:
if (spincontrol->value->f > spincontrol->max.f)
spincontrol->value->f = spincontrol->max.f;
else if (spincontrol->value->f < spincontrol->min.f)
spincontrol->value->f = spincontrol->min.f;
break;
}
}
static void FinishEditing(txt_spincontrol_t *spincontrol)
{
switch (spincontrol->type)
{
case TXT_SPINCONTROL_INT:
spincontrol->value->i = atoi(spincontrol->buffer);
break;
case TXT_SPINCONTROL_FLOAT:
spincontrol->value->f = (float) atof(spincontrol->buffer);
break;
}
spincontrol->editing = 0;
EnforceLimits(spincontrol);
}
static int TXT_SpinControlKeyPress(TXT_UNCAST_ARG(spincontrol), int key)
{
TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
// Enter to enter edit mode
if (spincontrol->editing)
{
if (key == KEY_ENTER)
{
FinishEditing(spincontrol);
return 1;
}
if (key == KEY_ESCAPE)
{
// Abort without saving value
spincontrol->editing = 0;
return 1;
}
if (isdigit(key) || key == '-' || key == '.')
{
AddCharacter(spincontrol, key);
return 1;
}
if (key == KEY_BACKSPACE)
{
Backspace(spincontrol);
return 1;
}
}
else
{
// Non-editing mode
if (key == KEY_ENTER)
{
spincontrol->editing = 1;
TXT_StringCopy(spincontrol->buffer, "", spincontrol->buffer_len);
return 1;
}
if (key == KEY_LEFTARROW)
{
switch (spincontrol->type)
{
case TXT_SPINCONTROL_INT:
spincontrol->value->i -= spincontrol->step.i;
break;
case TXT_SPINCONTROL_FLOAT:
spincontrol->value->f -= spincontrol->step.f;
break;
}
EnforceLimits(spincontrol);
return 1;
}
if (key == KEY_RIGHTARROW)
{
switch (spincontrol->type)
{
case TXT_SPINCONTROL_INT:
spincontrol->value->i += spincontrol->step.i;
break;
case TXT_SPINCONTROL_FLOAT:
spincontrol->value->f += spincontrol->step.f;
break;
}
EnforceLimits(spincontrol);
return 1;
}
}
return 0;
}
static void TXT_SpinControlMousePress(TXT_UNCAST_ARG(spincontrol),
int x, int y, int b)
{
TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
unsigned int rel_x;
rel_x = x - spincontrol->widget.x;
if (rel_x < 2)
{
TXT_SpinControlKeyPress(spincontrol, KEY_LEFTARROW);
}
else if (rel_x >= spincontrol->widget.w - 2)
{
TXT_SpinControlKeyPress(spincontrol, KEY_RIGHTARROW);
}
}
static void TXT_SpinControlFocused(TXT_UNCAST_ARG(spincontrol), int focused)
{
TXT_CAST_ARG(txt_spincontrol_t, spincontrol);
FinishEditing(spincontrol);
}
txt_widget_class_t txt_spincontrol_class =
{
TXT_AlwaysSelectable,
TXT_SpinControlSizeCalc,
TXT_SpinControlDrawer,
TXT_SpinControlKeyPress,
TXT_SpinControlDestructor,
TXT_SpinControlMousePress,
NULL,
TXT_SpinControlFocused,
};
static txt_spincontrol_t *TXT_BaseSpinControl(void)
{
txt_spincontrol_t *spincontrol;
spincontrol = malloc(sizeof(txt_spincontrol_t));
TXT_InitWidget(spincontrol, &txt_spincontrol_class);
spincontrol->buffer_len = 25;
spincontrol->buffer = malloc(spincontrol->buffer_len);
TXT_StringCopy(spincontrol->buffer, "", spincontrol->buffer_len);
spincontrol->editing = 0;
return spincontrol;
}
txt_spincontrol_t *TXT_NewSpinControl(int *value, int min, int max)
{
txt_spincontrol_t *spincontrol;
spincontrol = TXT_BaseSpinControl();
spincontrol->type = TXT_SPINCONTROL_INT;
spincontrol->value = (void *) value;
spincontrol->min.i = min;
spincontrol->max.i = max;
spincontrol->step.i = 1;
return spincontrol;
}
txt_spincontrol_t *TXT_NewFloatSpinControl(float *value, float min, float max)
{
txt_spincontrol_t *spincontrol;
spincontrol = TXT_BaseSpinControl();
spincontrol->type = TXT_SPINCONTROL_FLOAT;
spincontrol->value = (void *) value;
spincontrol->min.f = min;
spincontrol->max.f = max;
spincontrol->step.f = 0.1f;
return spincontrol;
}
@@ -0,0 +1,78 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_SPINCONTROL_H
#define TXT_SPINCONTROL_H
/**
* @file txt_spinctrl.h
*
* Spin control widget.
*/
/**
* Spin control widget.
*
* A spin control widget works as an input box that can be used to
* set numeric values, but also has buttons that allow its value
* to be increased or decreased.
*/
typedef struct txt_spincontrol_s txt_spincontrol_t;
typedef enum
{
TXT_SPINCONTROL_INT,
TXT_SPINCONTROL_FLOAT,
} txt_spincontrol_type_t;
#include "txt_widget.h"
struct txt_spincontrol_s
{
txt_widget_t widget;
txt_spincontrol_type_t type;
union { float f; int i; } min, max, *value, step;
int editing;
char *buffer;
size_t buffer_len;
};
/**
* Create a new spin control widget tracking an integer value.
*
* @param value Pointer to the variable containing the value
* displayed in the widget.
* @param min Minimum value that may be set.
* @param max Maximum value that may be set.
* @return Pointer to the new spin control widget.
*/
txt_spincontrol_t *TXT_NewSpinControl(int *value, int min, int max);
/**
* Create a new spin control widget tracking a float value.
*
* @param value Pointer to the variable containing the value
* displayed in the widget.
* @param min Minimum value that may be set.
* @param max Maximum value that may be set.
* @return Pointer to the new spin control widget.
*/
txt_spincontrol_t *TXT_NewFloatSpinControl(float *value, float min, float max);
#endif /* #ifndef TXT_SPINCONTROL_H */
@@ -0,0 +1,72 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_strut.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_window.h"
static void TXT_StrutSizeCalc(TXT_UNCAST_ARG(strut))
{
TXT_CAST_ARG(txt_strut_t, strut);
// Minimum width is the string length + two spaces for padding
strut->widget.w = strut->width;
strut->widget.h = strut->height;
}
static void TXT_StrutDrawer(TXT_UNCAST_ARG(strut))
{
// Nothing is drawn for a strut.
}
static void TXT_StrutDestructor(TXT_UNCAST_ARG(strut))
{
}
static int TXT_StrutKeyPress(TXT_UNCAST_ARG(strut), int key)
{
return 0;
}
txt_widget_class_t txt_strut_class =
{
TXT_NeverSelectable,
TXT_StrutSizeCalc,
TXT_StrutDrawer,
TXT_StrutKeyPress,
TXT_StrutDestructor,
NULL,
NULL,
};
txt_strut_t *TXT_NewStrut(int width, int height)
{
txt_strut_t *strut;
strut = malloc(sizeof(txt_strut_t));
TXT_InitWidget(strut, &txt_strut_class);
strut->width = width;
strut->height = height;
return strut;
}
@@ -0,0 +1,54 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_STRUT_H
#define TXT_STRUT_H
/**
* @file txt_strut.h
*
* Strut widget.
*/
/**
* Strut widget.
*
* A strut is a widget that takes up a fixed amount of space. It can
* be visualised as a transparent box. Struts are used to provide
* spacing between widgets.
*/
typedef struct txt_strut_s txt_strut_t;
#include "txt_widget.h"
struct txt_strut_s
{
txt_widget_t widget;
int width;
int height;
};
/**
* Create a new strut.
*
* @param width Width of the strut, in characters.
* @param height Height of the strut, in characters.
*/
txt_strut_t *TXT_NewStrut(int width, int height);
#endif /* #ifndef TXT_STRUT_H */
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,245 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_TABLE_H
#define TXT_TABLE_H
/**
* @file txt_table.h
*
* Table widget.
*/
/**
* Magic value that if used in a table, will indicate that the cell is
* empty and the widget in the cell to the left can overflow into it.
*/
#define TXT_TABLE_OVERFLOW_RIGHT (&txt_table_overflow_right)
/**
* Magic value that if used in a table, will indicate that the cell is
* empty and the widget in the cell above it can overflow down into it.
*/
#define TXT_TABLE_OVERFLOW_DOWN (&txt_table_overflow_down)
/**
* Magic value that if given to @ref TXT_AddWidget(), will pad out all
* columns until the end of line.
*/
#define TXT_TABLE_EOL (&txt_table_eol)
/**
* Indicates an empty space to @ref TXT_AddWidgets(). Equivalent to
* TXT_AddWidget(table, NULL), except that NULL is used by TXT_AddWidgets()
* to indicate the end of input.
*/
#define TXT_TABLE_EMPTY (&txt_table_empty)
/**
* Table widget.
*
* A table is a widget that contains other widgets. It may have
* multiple columns, in which case the child widgets are laid out
* in a grid. Columns automatically grow as necessary, although
* minimum column widths can be set using @ref TXT_SetColumnWidths.
*
* To create a new table, use @ref TXT_NewTable. It is also
* possible to use @ref TXT_NewHorizBox to create a table, specifying
* widgets to place inside a horizontal list. A vertical list is
* possible simply by creating a table containing a single column.
*/
typedef struct txt_table_s txt_table_t;
#include "txt_widget.h"
struct txt_table_s
{
txt_widget_t widget;
// Widgets in this table
// The widget at (x,y) in the table is widgets[columns * y + x]
txt_widget_t **widgets;
int num_widgets;
// Number of columns
int columns;
// Currently selected:
int selected_x;
int selected_y;
};
extern txt_widget_class_t txt_table_class;
extern txt_widget_t txt_table_overflow_right;
extern txt_widget_t txt_table_overflow_down;
extern txt_widget_t txt_table_eol;
extern txt_widget_t txt_table_empty;
void TXT_InitTable(txt_table_t *table, int columns);
/**
* Create a new table.
*
* @param columns The number of columns in the new table.
* @return Pointer to the new table structure.
*/
txt_table_t *TXT_NewTable(int columns);
/**
* Create a new table and populate it with provided widgets.
*
* The arguments to this function are variable. Each argument must be a
* pointer to a widget, and the list is terminated with a NULL.
*
* @param columns The number of columns in the new table.
* @return Pointer to the new table structure.
*/
txt_table_t *TXT_MakeTable(int columns, ...);
/**
* Create a table containing the specified widgets packed horizontally,
* from left to right.
*
* The arguments to this function are variable. Each argument must
* be a pointer to a widget, and the list is terminated with a
* NULL.
*
* @return Pointer to the new table structure.
*/
txt_table_t *TXT_NewHorizBox(TXT_UNCAST_ARG(first_widget), ...);
/**
* Get the currently selected widget within a table.
*
* This function will recurse through subtables if necessary.
*
* @param table The table.
* @return Pointer to the widget that is currently selected.
*/
txt_widget_t *TXT_GetSelectedWidget(TXT_UNCAST_ARG(table));
/**
* Add a widget to a table.
*
* Widgets are added to tables horizontally, from left to right.
* For example, for a table with three columns, the first call
* to this function will add a widget to the first column, the second
* call to the second column, the third call to the third column,
* and the fourth will return to the first column, starting a new
* row.
*
* For adding many widgets, it may be easier to use
* @ref TXT_AddWidgets.
*
* @param table The table.
* @param widget The widget to add.
*/
void TXT_AddWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget));
/**
* Add multiple widgets to a table.
*
* Widgets are added as described in the documentation for the
* @ref TXT_AddWidget function. This function adds multiple
* widgets. The number of arguments is variable, and the argument
* list must be terminated by a NULL pointer.
*
* @param table The table.
*/
void TXT_AddWidgets(TXT_UNCAST_ARG(table), ...);
/**
* Select the given widget that is contained within the specified
* table.
*
* This function will recursively search through subtables if
* necessary.
*
* @param table The table.
* @param widget The widget to select.
* @return Non-zero (true) if it has been selected,
* or zero (false) if it was not found within
* this table.
*/
int TXT_SelectWidget(TXT_UNCAST_ARG(table), TXT_UNCAST_ARG(widget));
/**
* Change the number of columns in the table.
*
* Existing widgets in the table will be preserved, unless the change
* reduces the number of columns, in which case the widgets from the
* 'deleted' columns will be freed.
*
* This function can be useful for changing the number of columns in
* a window, which by default are tables containing a single column.
*
* @param table The table.
* @param new_columns The new number of columns.
*/
void TXT_SetTableColumns(TXT_UNCAST_ARG(table), int new_columns);
/**
* Set the widths of the columns of the table.
*
* The arguments to this function are variable, and correspond
* to the number of columns in the table. For example, if a table
* has five columns, the width of each of the five columns must be
* specified.
*
* The width values are in number of characters.
*
* Note that this function only sets the minimum widths for columns;
* if the columns contain widgets that are wider than the widths
* specified, they will be larger.
*
* @param table The table.
*/
void TXT_SetColumnWidths(TXT_UNCAST_ARG(table), ...);
/**
* Remove all widgets from a table.
*
* @param table The table.
*/
void TXT_ClearTable(TXT_UNCAST_ARG(table));
/**
* Hack to move the selection in a table by a 'page', triggered by the
* scrollpane. This acts as per the keyboard events for the arrows, but moves
* the selection by at least the specified number of characters.
*
* @param table The table.
* @param pagex Minimum distance to move the selection horizontally.
* @param pagey Minimum distance to move the selection vertically.
* @return Non-zero if the selection has been changed.
*/
int TXT_PageTable(TXT_UNCAST_ARG(table), int pagex, int pagey);
#endif /* #ifndef TXT_TABLE_T */
@@ -0,0 +1,154 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "txt_utf8.h"
// Encode a Unicode character as UTF-8, storing it in the buffer 'p'
// and returning the new, incremented position.
char *TXT_EncodeUTF8(char *p, unsigned int c)
{
if (c < 0x80) // 1 character (ASCII):
{
p[0] = c;
return p + 1;
}
else if (c < 0x800) // 2 character:
{
p[0] = 0xc0 | (c >> 6);
p[1] = 0x80 | (c & 0x3f);
return p + 2;
}
else if (c < 0x10000) // 3 chacater:
{
p[0] = 0xe0 | (c >> 12);
p[1] = 0x80 | ((c >> 6) & 0x3f);
p[2] = 0x80 | (c & 0x3f);
return p + 3;
}
else if (c < 0x200000) // 4 character:
{
p[0] = 0xf0 | (c >> 18);
p[1] = 0x80 | ((c >> 12) & 0x3f);
p[2] = 0x80 | ((c >> 6) & 0x3f);
p[3] = 0x80 | (c & 0x3f);
return p + 4;
}
else
{
// Too big!
return p;
}
}
// Decode UTF-8 character, incrementing *ptr over the decoded bytes.
unsigned int TXT_DecodeUTF8(const char **ptr)
{
const char *p = *ptr;
unsigned int c;
// UTF-8 decode.
if ((*p & 0x80) == 0) // 1 character (ASCII):
{
c = *p;
*ptr += 1;
}
else if ((p[0] & 0xe0) == 0xc0 // 2 character:
&& (p[1] & 0xc0) == 0x80)
{
c = ((p[0] & 0x1f) << 6)
| (p[1] & 0x3f);
*ptr += 2;
}
else if ((p[0] & 0xf0) == 0xe0 // 3 character:
&& (p[1] & 0xc0) == 0x80
&& (p[2] & 0xc0) == 0x80)
{
c = ((p[0] & 0x0f) << 12)
| ((p[1] & 0x3f) << 6)
| (p[2] & 0x3f);
*ptr += 3;
}
else if ((p[0] & 0xf8) == 0xf0 // 4 character:
&& (p[1] & 0xc0) == 0x80
&& (p[2] & 0xc0) == 0x80
&& (p[3] & 0xc0) == 0x80)
{
c = ((p[0] & 0x07) << 18)
| ((p[1] & 0x3f) << 12)
| ((p[2] & 0x3f) << 6)
| (p[3] & 0x3f);
*ptr += 4;
}
else
{
// Decode failure.
// Don't bother with 5/6 byte sequences.
c = 0;
}
return c;
}
// Count the number of characters in a UTF-8 string.
unsigned int TXT_UTF8_Strlen(const char *s)
{
const char *p;
unsigned int result = 0;
unsigned int c;
for (p = s; *p != '\0';)
{
c = TXT_DecodeUTF8(&p);
if (c == 0)
{
break;
}
++result;
}
return result;
}
// Skip past the first n characters in a UTF-8 string.
char *TXT_UTF8_SkipChars(const char *s, unsigned int n)
{
unsigned int i;
const char *p;
p = s;
for (i = 0; i < n; ++i)
{
if (TXT_DecodeUTF8(&p) == 0)
{
break;
}
}
return (char *) p;
}
@@ -0,0 +1,26 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_UTF8_H
#define TXT_UTF8_H
#include <stdarg.h>
char *TXT_EncodeUTF8(char *p, unsigned int c);
unsigned int TXT_DecodeUTF8(const char **ptr);
unsigned int TXT_UTF8_Strlen(const char *s);
char *TXT_UTF8_SkipChars(const char *s, unsigned int n);
#endif /* #ifndef TXT_UTF8_H */
@@ -0,0 +1,381 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include "txt_io.h"
#include "txt_widget.h"
#include "txt_gui.h"
#include "txt_desktop.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
typedef struct
{
char *signal_name;
TxtWidgetSignalFunc func;
void *user_data;
} txt_callback_t;
struct txt_callback_table_s
{
int refcount;
txt_callback_t *callbacks;
int num_callbacks;
};
txt_callback_table_t *TXT_NewCallbackTable(void)
{
txt_callback_table_t *table;
table = malloc(sizeof(txt_callback_table_t));
table->callbacks = NULL;
table->num_callbacks = 0;
table->refcount = 1;
return table;
}
void TXT_RefCallbackTable(txt_callback_table_t *table)
{
++table->refcount;
}
void TXT_UnrefCallbackTable(txt_callback_table_t *table)
{
int i;
--table->refcount;
if (table->refcount == 0)
{
// No more references to this table
for (i=0; i<table->num_callbacks; ++i)
{
free(table->callbacks[i].signal_name);
}
free(table->callbacks);
free(table);
}
}
void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class)
{
TXT_CAST_ARG(txt_widget_t, widget);
widget->widget_class = widget_class;
widget->callback_table = TXT_NewCallbackTable();
widget->parent = NULL;
// Not focused until we hear otherwise.
widget->focused = 0;
// Visible by default.
widget->visible = 1;
// Align left by default
widget->align = TXT_HORIZ_LEFT;
// No helplabel by default
widget->is_helplabel_set = 0;
}
void TXT_SignalConnect(TXT_UNCAST_ARG(widget),
const char *signal_name,
TxtWidgetSignalFunc func,
void *user_data)
{
TXT_CAST_ARG(txt_widget_t, widget);
txt_callback_table_t *table;
txt_callback_t *callback;
table = widget->callback_table;
// Add a new callback to the table
table->callbacks
= realloc(table->callbacks,
sizeof(txt_callback_t) * (table->num_callbacks + 1));
callback = &table->callbacks[table->num_callbacks];
++table->num_callbacks;
callback->signal_name = strdup(signal_name);
callback->func = func;
callback->user_data = user_data;
}
void TXT_EmitSignal(TXT_UNCAST_ARG(widget), const char *signal_name)
{
TXT_CAST_ARG(txt_widget_t, widget);
txt_callback_table_t *table;
int i;
table = widget->callback_table;
// Don't destroy the table while we're searching through it
// (one of the callbacks may destroy this window)
TXT_RefCallbackTable(table);
// Search the table for all callbacks with this name and invoke
// the functions.
for (i=0; i<table->num_callbacks; ++i)
{
if (!strcmp(table->callbacks[i].signal_name, signal_name))
{
table->callbacks[i].func(widget, table->callbacks[i].user_data);
}
}
// Finished using the table
TXT_UnrefCallbackTable(table);
}
void TXT_CalcWidgetSize(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
widget->widget_class->size_calc(widget);
}
void TXT_DrawWidget(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
txt_saved_colors_t colors;
// The drawing function might change the fg/bg colors,
// so make sure we restore them after it's done.
TXT_SaveColors(&colors);
// For convenience...
TXT_GotoXY(widget->x, widget->y);
// Call drawer method
widget->widget_class->drawer(widget);
TXT_RestoreColors(&colors);
}
void TXT_DestroyWidget(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
widget->widget_class->destructor(widget);
TXT_UnrefCallbackTable(widget->callback_table);
free(widget);
}
int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key)
{
TXT_CAST_ARG(txt_widget_t, widget);
if (widget->widget_class->key_press != NULL)
{
return widget->widget_class->key_press(widget, key);
}
return 0;
}
void TXT_SetWidgetFocus(TXT_UNCAST_ARG(widget), int focused)
{
TXT_CAST_ARG(txt_widget_t, widget);
if (widget == NULL)
{
return;
}
if (widget->focused != focused)
{
widget->focused = focused;
if (widget->widget_class->focus_change != NULL)
{
widget->widget_class->focus_change(widget, focused);
}
}
}
void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align)
{
TXT_CAST_ARG(txt_widget_t, widget);
widget->align = horiz_align;
}
void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b)
{
TXT_CAST_ARG(txt_widget_t, widget);
if (widget->widget_class->mouse_press != NULL)
{
widget->widget_class->mouse_press(widget, x, y, b);
}
}
void TXT_LayoutWidget(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
if (widget->widget_class->layout != NULL)
{
widget->widget_class->layout(widget);
}
}
int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget))
{
return 1;
}
int TXT_NeverSelectable(TXT_UNCAST_ARG(widget))
{
return 0;
}
int TXT_SelectableWidget(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
if (widget->widget_class->selectable != NULL)
{
return widget->widget_class->selectable(widget);
}
else
{
return 0;
}
}
int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle))
{
TXT_CAST_ARG(txt_widget_t, haystack);
TXT_CAST_ARG(txt_widget_t, needle);
while (needle != NULL)
{
if (needle == haystack)
{
return 1;
}
needle = needle->parent;
}
return 0;
}
int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
txt_window_t *active_window;
int x, y;
// We can only be hovering over widgets in the active window.
active_window = TXT_GetActiveWindow();
if (active_window == NULL || !TXT_ContainsWidget(active_window, widget))
{
return 0;
}
// Is the mouse cursor within the bounds of the widget?
TXT_GetMousePosition(&x, &y);
return (x >= widget->x && x < widget->x + widget->w
&& y >= widget->y && y < widget->y + widget->h);
}
void TXT_SetHelpLabel(TXT_UNCAST_ARG(widget), const char* helplabel)
{
TXT_CAST_ARG(txt_widget_t, widget);
widget->helplabel = strdup(helplabel);
widget->is_helplabel_set = 1;
}
void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget))
{
TXT_CAST_ARG(txt_widget_t, widget);
txt_window_t* active_window;
active_window = TXT_GetActiveWindow();
if (widget->helplabel == NULL)
{
widget->helplabel = "";
}
// When helplabel is not set for widget draw nothing
if (widget->is_helplabel_set != 1)
{
TXT_SetHelpLabel(widget, "");
}
// When in active window no widget is hovering or focused deactivate helplabel
if (!TXT_ContainsWidget(active_window, widget))
{
TXT_DrawHelpLabel("");
}
if (widget->focused)
{
TXT_FGColor(TXT_COLOR_BLACK);
TXT_BGColor(TXT_COLOR_GREY, 0);
// Set helplabel when widget focused
if (!TXT_HoveringOverWidget(active_window) && widget->is_helplabel_set == 1)
{
TXT_DrawHelpLabel(widget->helplabel);
}
}
else if (TXT_HoveringOverWidget(widget))
{
TXT_BGColor(TXT_HOVER_BACKGROUND, 0);
}
if (TXT_HoveringOverWidget(widget) && widget->is_helplabel_set == 1)
{
// Set helplabel when mouse hovering over widget
TXT_DrawHelpLabel(widget->helplabel);
}
else
{
// Use normal window background.
}
}
@@ -0,0 +1,196 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_WIDGET_H
#define TXT_WIDGET_H
/**
* @file txt_widget.h
*
* Base "widget" GUI component class.
*/
#ifndef DOXYGEN
#define TXT_UNCAST_ARG_NAME(name) uncast_ ## name
#define TXT_UNCAST_ARG(name) void * TXT_UNCAST_ARG_NAME(name)
#define TXT_CAST_ARG(type, name) type *name = (type *) uncast_ ## name
#else
#define TXT_UNCAST_ARG(name) txt_widget_t *name
#endif
typedef enum
{
TXT_VERT_TOP,
TXT_VERT_CENTER,
TXT_VERT_BOTTOM,
} txt_vert_align_t;
typedef enum
{
TXT_HORIZ_LEFT,
TXT_HORIZ_CENTER,
TXT_HORIZ_RIGHT,
} txt_horiz_align_t;
/**
* A GUI widget.
*
* A widget is an individual component of a GUI. Various different widget
* types exist.
*
* Widgets may emit signals. The types of signal emitted by a widget
* depend on the type of the widget. It is possible to be notified
* when a signal occurs using the @ref TXT_SignalConnect function.
*/
typedef struct txt_widget_s txt_widget_t;
typedef struct txt_widget_class_s txt_widget_class_t;
typedef struct txt_callback_table_s txt_callback_table_t;
typedef void (*TxtWidgetSizeCalc)(TXT_UNCAST_ARG(widget));
typedef void (*TxtWidgetDrawer)(TXT_UNCAST_ARG(widget));
typedef void (*TxtWidgetDestroy)(TXT_UNCAST_ARG(widget));
typedef int (*TxtWidgetKeyPress)(TXT_UNCAST_ARG(widget), int key);
typedef void (*TxtWidgetSignalFunc)(TXT_UNCAST_ARG(widget), void *user_data);
typedef void (*TxtMousePressFunc)(TXT_UNCAST_ARG(widget), int x, int y, int b);
typedef void (*TxtWidgetLayoutFunc)(TXT_UNCAST_ARG(widget));
typedef int (*TxtWidgetSelectableFunc)(TXT_UNCAST_ARG(widget));
typedef void (*TxtWidgetFocusFunc)(TXT_UNCAST_ARG(widget), int focused);
struct txt_widget_class_s
{
TxtWidgetSelectableFunc selectable;
TxtWidgetSizeCalc size_calc;
TxtWidgetDrawer drawer;
TxtWidgetKeyPress key_press;
TxtWidgetDestroy destructor;
TxtMousePressFunc mouse_press;
TxtWidgetLayoutFunc layout;
TxtWidgetFocusFunc focus_change;
};
struct txt_widget_s
{
txt_widget_class_t *widget_class;
txt_callback_table_t *callback_table;
int visible;
txt_horiz_align_t align;
int focused;
// These are set automatically when the window is drawn and should
// not be set manually.
int x, y;
unsigned int w, h;
// Pointer up to parent widget that contains this widget.
txt_widget_t *parent;
// Set helplabel to widget
const char* helplabel;
// Call helplabel draw function only when helplabel is set for widget
int is_helplabel_set;
};
void TXT_InitWidget(TXT_UNCAST_ARG(widget), txt_widget_class_t *widget_class);
void TXT_CalcWidgetSize(TXT_UNCAST_ARG(widget));
void TXT_DrawWidget(TXT_UNCAST_ARG(widget));
void TXT_EmitSignal(TXT_UNCAST_ARG(widget), const char *signal_name);
int TXT_WidgetKeyPress(TXT_UNCAST_ARG(widget), int key);
void TXT_WidgetMousePress(TXT_UNCAST_ARG(widget), int x, int y, int b);
void TXT_DestroyWidget(TXT_UNCAST_ARG(widget));
void TXT_LayoutWidget(TXT_UNCAST_ARG(widget));
int TXT_AlwaysSelectable(TXT_UNCAST_ARG(widget));
int TXT_NeverSelectable(TXT_UNCAST_ARG(widget));
void TXT_SetWidgetFocus(TXT_UNCAST_ARG(widget), int focused);
/**
* Set a callback function to be invoked when a signal occurs.
*
* @param widget The widget to watch.
* @param signal_name The signal to watch.
* @param func The callback function to invoke.
* @param user_data User-specified pointer to pass to the callback function.
*/
void TXT_SignalConnect(TXT_UNCAST_ARG(widget), const char *signal_name,
TxtWidgetSignalFunc func, void *user_data);
/**
* Set the policy for how a widget should be aligned within a table.
* By default, widgets are aligned to the left of the column.
*
* @param widget The widget.
* @param horiz_align The alignment to use.
*/
void TXT_SetWidgetAlign(TXT_UNCAST_ARG(widget), txt_horiz_align_t horiz_align);
/**
* Query whether a widget is selectable with the cursor.
*
* @param widget The widget.
* @return Non-zero if the widget is selectable.
*/
int TXT_SelectableWidget(TXT_UNCAST_ARG(widget));
/**
* Query whether the mouse is hovering over the specified widget.
*
* @param widget The widget.
* @return Non-zero if the mouse cursor is over the widget.
*/
int TXT_HoveringOverWidget(TXT_UNCAST_ARG(widget));
/**
* Set the background to draw the specified widget, depending on
* whether it is selected and the mouse is hovering over it.
*
* @param widget The widget.
*/
void TXT_SetWidgetBG(TXT_UNCAST_ARG(widget));
/**
* Query whether the specified widget is contained within another
* widget.
*
* @param haystack The widget that might contain needle.
* @param needle The widget being queried.
*/
int TXT_ContainsWidget(TXT_UNCAST_ARG(haystack), TXT_UNCAST_ARG(needle));
/**
* Set helplabel on left side of bottom banner
*
* @ param widget The widget
* @ param helplabel The helplabel to show on bottom banner
*/
void TXT_SetHelpLabel(TXT_UNCAST_ARG(widget), const char* helplabel);
#endif /* #ifndef TXT_WIDGET_H */
@@ -0,0 +1,687 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "doomkeys.h"
#include "txt_label.h"
#include "txt_desktop.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_separator.h"
#include "txt_window.h"
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shellapi.h>
#endif
#ifdef _MSC_VER
#define strdup _strdup
#endif
void TXT_SetWindowAction(txt_window_t *window,
txt_horiz_align_t position,
TXT_UNCAST_ARG(action))
{
TXT_CAST_ARG(txt_widget_t, action);
if (window->actions[position] != NULL)
{
TXT_DestroyWidget(window->actions[position]);
}
window->actions[position] = action;
// Maintain parent pointer.
if (action != NULL)
{
action->parent = &window->table.widget;
}
}
txt_window_t *TXT_NewCustomWindow(const char *title, int titlecolor, int active_bgcolor, int inactive_bgcolor, int active_fgcolor, int inactive_fgcolor, int framecolor, int sepcolor)
{
int i;
txt_window_t* win;
win = malloc(sizeof(txt_window_t));
TXT_InitTable(&win->table, 1);
if (title == NULL)
{
win->title = NULL;
}
else
{
win->title = strdup(title);
}
win->x = TXT_SCREEN_W / 2;
win->y = TXT_SCREEN_H / 2;
win->horiz_align = TXT_HORIZ_CENTER;
win->vert_align = TXT_VERT_CENTER;
win->key_listener = NULL;
win->mouse_listener = NULL;
win->help_url = NULL;
win->titlecolor = titlecolor;
win->active_bgcolor = active_bgcolor;
win->inactive_bgcolor = inactive_bgcolor;
win->active_fgcolor = active_fgcolor;
win->inactive_fgcolor = inactive_fgcolor;
win->framecolor = framecolor;
win->sepcolor = sepcolor;
win->customwin = 1;
TXT_AddWidget(win, TXT_NewSeparator(NULL));
for (i = 0; i < 3; ++i)
{
win->actions[i] = NULL;
}
TXT_AddDesktopWindow(win);
// Default actions
TXT_SetWindowAction(win, TXT_HORIZ_LEFT, TXT_NewWindowEscapeAction(win));
TXT_SetWindowAction(win, TXT_HORIZ_RIGHT, TXT_NewWindowSelectAction(win));
return win;
}
txt_window_t *TXT_NewWindow(const char *title)
{
int i;
txt_window_t *win;
win = malloc(sizeof(txt_window_t));
TXT_InitTable(&win->table, 1);
if (title == NULL)
{
win->title = NULL;
}
else
{
win->title = strdup(title);
}
win->x = TXT_SCREEN_W / 2;
win->y = TXT_SCREEN_H / 2;
win->horiz_align = TXT_HORIZ_CENTER;
win->vert_align = TXT_VERT_CENTER;
win->key_listener = NULL;
win->mouse_listener = NULL;
win->help_url = NULL;
win->customwin = 0;
TXT_AddWidget(win, TXT_NewSeparator(NULL));
for (i=0; i<3; ++i)
{
win->actions[i] = NULL;
}
TXT_AddDesktopWindow(win);
// Default actions
TXT_SetWindowAction(win, TXT_HORIZ_LEFT, TXT_NewWindowEscapeAction(win));
TXT_SetWindowAction(win, TXT_HORIZ_RIGHT, TXT_NewWindowSelectAction(win));
return win;
}
void TXT_CloseWindow(txt_window_t *window)
{
int i;
TXT_EmitSignal(window, "closed");
TXT_RemoveDesktopWindow(window);
free(window->title);
// Destroy all actions
for (i=0; i<3; ++i)
{
if (window->actions[i] != NULL)
{
TXT_DestroyWidget(window->actions[i]);
}
}
// Destroy table and window
TXT_DestroyWidget(window);
}
static void CalcWindowPosition(txt_window_t *window)
{
switch (window->horiz_align)
{
case TXT_HORIZ_LEFT:
window->window_x = window->x;
break;
case TXT_HORIZ_CENTER:
window->window_x = window->x - (window->window_w / 2);
break;
case TXT_HORIZ_RIGHT:
window->window_x = window->x - (window->window_w - 1);
break;
}
switch (window->vert_align)
{
case TXT_VERT_TOP:
window->window_y = window->y;
break;
case TXT_VERT_CENTER:
window->window_y = window->y - (window->window_h / 2);
break;
case TXT_VERT_BOTTOM:
window->window_y = window->y - (window->window_h - 1);
break;
}
}
static void LayoutActionArea(txt_window_t *window)
{
txt_widget_t *widget;
int space_available;
int space_left_offset;
// We need to calculate the available horizontal space for the center
// action widget, so that we can center it within it.
// To start with, we have the entire action area available.
space_available = window->window_w;
space_left_offset = 0;
// Left action
if (window->actions[TXT_HORIZ_LEFT] != NULL)
{
widget = window->actions[TXT_HORIZ_LEFT];
TXT_CalcWidgetSize(widget);
widget->x = window->window_x + 1;
widget->y = window->window_y + window->window_h - widget->h - 1;
// Adjust available space:
space_available -= widget->w;
space_left_offset += widget->w;
TXT_LayoutWidget(widget);
}
// Draw the right action
if (window->actions[TXT_HORIZ_RIGHT] != NULL)
{
widget = window->actions[TXT_HORIZ_RIGHT];
TXT_CalcWidgetSize(widget);
widget->x = window->window_x + window->window_w - 1 - widget->w;
widget->y = window->window_y + window->window_h - widget->h - 1;
// Adjust available space:
space_available -= widget->w;
TXT_LayoutWidget(widget);
}
// Draw the center action
if (window->actions[TXT_HORIZ_CENTER] != NULL)
{
widget = window->actions[TXT_HORIZ_CENTER];
TXT_CalcWidgetSize(widget);
// The left and right widgets have left a space sandwiched between
// them. Center this widget within that space.
widget->x = window->window_x
+ space_left_offset
+ (space_available - widget->w) / 2;
widget->y = window->window_y + window->window_h - widget->h - 1;
TXT_LayoutWidget(widget);
}
}
static void DrawActionArea(txt_window_t *window)
{
int i;
for (i=0; i<3; ++i)
{
if (window->actions[i] != NULL)
{
TXT_DrawWidget(window->actions[i]);
}
}
}
static void CalcActionAreaSize(txt_window_t *window,
unsigned int *w, unsigned int *h)
{
txt_widget_t *widget;
int i;
*w = 0;
*h = 0;
// Calculate the width of all the action widgets and use this
// to create an overall min. width of the action area
for (i=0; i<3; ++i)
{
widget = (txt_widget_t *) window->actions[i];
if (widget != NULL)
{
TXT_CalcWidgetSize(widget);
*w += widget->w;
if (widget->h > *h)
{
*h = widget->h;
}
}
}
}
// Sets size and position of all widgets in a window
void TXT_LayoutWindow(txt_window_t *window)
{
txt_widget_t *widgets = (txt_widget_t *) window;
unsigned int widgets_w;
unsigned int actionarea_w, actionarea_h;
// Calculate size of table
TXT_CalcWidgetSize(window);
// Widgets area: add one character of padding on each side
widgets_w = widgets->w + 2;
// Calculate the size of the action area
// Make window wide enough to action area
CalcActionAreaSize(window, &actionarea_w, &actionarea_h);
if (actionarea_w > widgets_w)
widgets_w = actionarea_w - 2;
// Set the window size based on widgets_w
window->window_w = widgets_w + 2;
window->window_h = widgets->h + 1;
// If the window has a title, add an extra two lines
if (window->title != NULL)
{
window->window_h += 2;
}
// If the window has an action area, add extra lines
if (actionarea_h > 0)
{
window->window_h += actionarea_h + 1;
}
// Use the x,y position as the centerpoint and find the location to
// draw the window.
CalcWindowPosition(window);
// Set the table size and position
widgets->w = widgets_w - 2;
// widgets->h (already set)
widgets->x = window->window_x + 2;
widgets->y = window->window_y;
if (window->title != NULL)
{
widgets->y += 2;
}
// Layout the table and action area
LayoutActionArea(window);
TXT_LayoutWidget(widgets);
}
void TXT_DrawWindow(txt_window_t *window)
{
txt_widget_t *widgets;
TXT_LayoutWindow(window);
if (window->table.widget.focused && window->customwin != 1)
{
TXT_BGColor(TXT_ACTIVE_WINDOW_BACKGROUND, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
}
else if (window->customwin != 1)
{
TXT_BGColor(TXT_INACTIVE_WINDOW_BACKGROUND, 0);
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
}
if (window->table.widget.focused && window->customwin == 1)
{
TXT_BGColor(window->active_bgcolor, 0);
TXT_FGColor(window->active_fgcolor);
}
else if (window->customwin == 1)
{
TXT_BGColor(window->inactive_bgcolor, 0);
TXT_FGColor(window->inactive_fgcolor);
}
// Draw the window
TXT_DrawWindowFrame(window->title,
window->window_x, window->window_y,
window->window_w, window->window_h,
window->titlecolor, window->framecolor,
window->customwin);
// Draw all widgets
TXT_DrawWidget(window);
// Draw an action area, if we have one
widgets = (txt_widget_t *) window;
if (widgets->y + widgets->h < window->window_y + window->window_h - 1)
{
// Separator for action area
TXT_DrawSeparator(window->window_x, widgets->y + widgets->h,
window->window_w, window->sepcolor, window->customwin);
// Action area at the window bottom
DrawActionArea(window);
}
}
void TXT_SetWindowPosition(txt_window_t *window,
txt_horiz_align_t horiz_align,
txt_vert_align_t vert_align,
int x, int y)
{
window->vert_align = vert_align;
window->horiz_align = horiz_align;
window->x = x;
window->y = y;
}
static int MouseButtonPress(txt_window_t *window, int b)
{
int x, y;
int i;
txt_widget_t *widgets;
txt_widget_t *widget;
// Lay out the window, set positions and sizes of all widgets
TXT_LayoutWindow(window);
// Get the current mouse position
TXT_GetMousePosition(&x, &y);
// Try the mouse button listener
// This happens whether it is in the window range or not
if (window->mouse_listener != NULL)
{
// Mouse listener can eat button presses
if (window->mouse_listener(window, x, y, b,
window->mouse_listener_data))
{
return 1;
}
}
// Is it within the table range?
widgets = (txt_widget_t *) window;
if (x >= widgets->x && x < (signed) (widgets->x + widgets->w)
&& y >= widgets->y && y < (signed) (widgets->y + widgets->h))
{
TXT_WidgetMousePress(window, x, y, b);
return 1;
}
// Was one of the action area buttons pressed?
for (i=0; i<3; ++i)
{
widget = window->actions[i];
if (widget != NULL
&& x >= widget->x && x < (signed) (widget->x + widget->w)
&& y >= widget->y && y < (signed) (widget->y + widget->h))
{
int was_focused;
// Main table temporarily loses focus when action area button
// is clicked. This way, any active input boxes that depend
// on having focus will save their values before the
// action is performed.
was_focused = window->table.widget.focused;
TXT_SetWidgetFocus(window, 0);
TXT_SetWidgetFocus(window, was_focused);
// Pass through mouse press.
TXT_WidgetMousePress(widget, x, y, b);
return 1;
}
}
return 0;
}
int TXT_WindowKeyPress(txt_window_t *window, int c)
{
int i;
// Is this a mouse button ?
if (c >= TXT_MOUSE_BASE && c < TXT_MOUSE_BASE + TXT_MAX_MOUSE_BUTTONS)
{
return MouseButtonPress(window, c);
}
// Try the window key spy
if (window->key_listener != NULL)
{
// key listener can eat keys
if (window->key_listener(window, c, window->key_listener_data))
{
return 1;
}
}
// Send to the currently selected widget:
if (TXT_WidgetKeyPress(window, c))
{
return 1;
}
// Try all of the action buttons
for (i=0; i<3; ++i)
{
if (window->actions[i] != NULL
&& TXT_WidgetKeyPress(window->actions[i], c))
{
return 1;
}
}
return 0;
}
void TXT_SetKeyListener(txt_window_t *window, TxtWindowKeyPress key_listener,
void *user_data)
{
window->key_listener = key_listener;
window->key_listener_data = user_data;
}
void TXT_SetMouseListener(txt_window_t *window,
TxtWindowMousePress mouse_listener,
void *user_data)
{
window->mouse_listener = mouse_listener;
window->mouse_listener_data = user_data;
}
void TXT_SetWindowFocus(txt_window_t *window, int focused)
{
TXT_SetWidgetFocus(window, focused);
}
void TXT_SetWindowHelpURL(txt_window_t *window, const char *help_url)
{
window->help_url = help_url;
}
#ifdef _WIN32
void TXT_OpenURL(const char *url)
{
ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL);
}
#else
void TXT_OpenURL(const char *url)
{
char *cmd;
size_t cmd_len;
int retval;
cmd_len = strlen(url) + 30;
cmd = malloc(cmd_len);
#if defined(__MACOSX__)
TXT_snprintf(cmd, cmd_len, "open \"%s\"", url);
#else
// The Unix situation sucks as usual, but the closest thing to a
// standard that exists is the xdg-utils package.
if (system("xdg-open --version 2>/dev/null") != 0)
{
fprintf(stderr,
"xdg-utils is not installed. Can't open this URL:\n%s\n", url);
free(cmd);
return;
}
TXT_snprintf(cmd, cmd_len, "xdg-open \"%s\"", url);
#endif
retval = system(cmd);
free(cmd);
if (retval != 0)
{
fprintf(stderr, "TXT_OpenURL: error executing '%s'; return code %d\n",
cmd, retval);
}
}
#endif /* #ifndef _WIN32 */
void TXT_OpenWindowHelpURL(txt_window_t *window)
{
if (window->help_url != NULL)
{
TXT_OpenURL(window->help_url);
}
}
txt_window_t* TXT_CustomMessageBox(const char* title, const char* message, int titlecolor, int active_bgcolor, int inactive_bgcolor, int active_fgcolor, int inactive_fgcolor, int framecolor, int sepcolor, ...)
{
txt_window_t* window;
char buf[256];
va_list args;
va_start(args, sepcolor);
TXT_vsnprintf(buf, sizeof(buf), message, args);
va_end(args);
window = TXT_NewCustomWindow(title, titlecolor, active_bgcolor, inactive_bgcolor, active_fgcolor, inactive_fgcolor, framecolor, sepcolor);
TXT_AddWidget(window, TXT_NewLabel(buf));
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
TXT_NewWindowEscapeAction(window));
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
return window;
}
txt_window_t *TXT_MessageBox(const char *title, const char *message, ...)
{
txt_window_t *window;
char buf[256];
va_list args;
va_start(args, message);
TXT_vsnprintf(buf, sizeof(buf), message, args);
va_end(args);
window = TXT_NewWindow(title);
TXT_AddWidget(window, TXT_NewLabel(buf));
TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
TXT_NewWindowEscapeAction(window));
TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
return window;
}
@@ -0,0 +1,289 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_WINDOW_H
#define TXT_WINDOW_H
/**
* @file txt_window.h
*
* Windows.
*/
/**
* A window.
*
* A window contains widgets, and may also be treated as a table
* (@ref txt_table_t) containing a single column.
*
* Windows can be created using @ref TXT_NewWindow and closed using
* @ref TXT_CloseWindow. When a window is closed, it emits the
* "closed" signal.
*
* In addition to the widgets within a window, windows also have
* a "tray" area at their bottom containing window action widgets.
* These widgets allow keyboard shortcuts to trigger common actions.
* Each window has three slots for keyboard shortcuts. By default,
* the left slot contains an action to close the window when the
* escape button is pressed, while the right slot contains an
* action to activate the currently-selected widget.
*/
typedef struct txt_window_s txt_window_t;
#include "txt_widget.h"
#include "txt_table.h"
#include "txt_window_action.h"
// Callback function for window key presses
typedef int (*TxtWindowKeyPress)(txt_window_t *window, int key,
void *user_data);
typedef int (*TxtWindowMousePress)(txt_window_t *window,
int x, int y, int b,
void *user_data);
struct txt_window_s
{
// Base class: all windows are tables with one column.
txt_table_t table;
// Window title
char *title;
// Screen coordinates of the window
txt_vert_align_t vert_align;
txt_horiz_align_t horiz_align;
int x, y;
// Actions that appear in the box at the bottom of the window
txt_widget_t *actions[3];
// Callback functions to invoke when keys/mouse buttons are pressed
TxtWindowKeyPress key_listener;
void *key_listener_data;
TxtWindowMousePress mouse_listener;
void *mouse_listener_data;
// These are set automatically when the window is drawn
int window_x, window_y;
unsigned int window_w, window_h;
// URL of a webpage with help about this window. If set, a help key
// indicator is shown while this window is active.
const char *help_url;
// Title color of the window
int titlecolor;
// Background color of the active window
int active_bgcolor;
// Background color of the inactive window
int inactive_bgcolor;
// Foreground color of the active window
int active_fgcolor;
// Foreground color of the inactive window
int inactive_fgcolor;
// Frame color of the window
int framecolor;
// Seperator color of the window
int sepcolor;
// True when TXT_NewCustomWindow is set
int customwin;
};
/**
* Open a new custom window.
*
* @param title Title to display in the titlebar of the new window
* (UTF-8 format).
* @param titlecolor Set color of title to window.
* @param active_bgcolor Set color of background to active window.
* @param inactive_bgcolor Set color of background to inactive window.
* @param active_fgcolor Set color of foreground to active window.
* @param inactive_fgcolor Set color of foreground to inactive window.
* @param framecolor Set color of frame to window.
* @param sepcolor Set color of separator to window.
* @return Pointer to a new @ref txt_window_t structure.
* representing the new window.
*/
txt_window_t* TXT_NewCustomWindow(const char* title, int titlecolor, int active_bgcolor, int inactive_bgcolor, int active_fgcolor, int inactive_fgcolor, int framecolor, int sepcolor);
/**
* Open a new window.
*
* @param title Title to display in the titlebar of the new window
* (UTF-8 format).
* @return Pointer to a new @ref txt_window_t structure
* representing the new window.
*/
txt_window_t *TXT_NewWindow(const char *title);
/**
* Close a window.
*
* @param window Tine window to close.
*/
void TXT_CloseWindow(txt_window_t *window);
/**
* Set the position of a window on the screen.
*
* The position is specified as a pair of x, y, coordinates on the
* screen. These specify the position of a particular point on the
* window. The following are some examples:
*
* <code>
* // Centered on the screen:
*
* TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_CENTER,
* TXT_SCREEN_W / 2, TXT_SCREEN_H / 2);
*
* // Horizontally centered, with top of the window on line 6:
*
* TXT_SetWindowPosition(window, TXT_HORIZ_CENTER, TXT_VERT_TOP,
* TXT_SCREEN_W / 2, 6);
*
* // Top-left of window at 20, 6:
*
* TXT_SetWindowPosition(window, TXT_HORIZ_LEFT, TXT_VERT_TOP, 20, 6);
* </code>
*
* @param window The window.
* @param horiz_align Horizontal location on the window for the X
* position.
* @param vert_align Vertical location on the window for the Y position.
* @param x X coordinate (horizontal axis) for window position.
* @param y Y coordinate (vertical axis) for window position.
*/
void TXT_SetWindowPosition(txt_window_t *window,
txt_horiz_align_t horiz_align,
txt_vert_align_t vert_align,
int x, int y);
/**
* Set a window action for a given window.
*
* Each window can have up to three window actions, which provide
* keyboard shortcuts that can be used within a given window.
*
* @param window The window.
* @param position The window action slot to set (left, center or right).
* @param action The window action widget. If this is NULL, any
* current window action in the given slot is removed.
*/
void TXT_SetWindowAction(txt_window_t *window, txt_horiz_align_t position,
TXT_UNCAST_ARG(action));
/**
* Set a callback function to be invoked whenever a key is pressed within
* a window.
*
* @param window The window.
* @param key_listener Callback function.
* @param user_data User-specified pointer to pass to the callback
* function.
*/
void TXT_SetKeyListener(txt_window_t *window,
TxtWindowKeyPress key_listener,
void *user_data);
/**
* Set a callback function to be invoked whenever a mouse button is pressed
* within a window.
*
* @param window The window.
* @param mouse_listener Callback function.
* @param user_data User-specified pointer to pass to the callback
* function.
*/
void TXT_SetMouseListener(txt_window_t *window,
TxtWindowMousePress mouse_listener,
void *user_data);
/**
* Open a window displaying a message.
*
* @param title Title of the window (UTF-8 format).
* @param message The message to display in the window (UTF-8 format).
* @return The new window.
*/
txt_window_t *TXT_MessageBox(const char *title, const char *message, ...);
/**
* Open a window displaying a message.
*
* @param title Title of the window (UTF-8 format).
* @param message The message to display in the window (UTF-8 format).
* @param titlecolor Set color of title to window.
* @param active_bgcolor Set color of background to active window.
* @param inactive_bgcolor Set color of background to inactive window.
* @param active_fgcolor Set color of foreground to active window.
* @param inactive_fgcolor Set color of foreground to inactive window.
* @param framecolor Set color of frame to window.
* @param sepcolor Set color of seperator to window.
* @return The new window.
*/
txt_window_t* TXT_CustomMessageBox(const char* title, const char* message, int titlecolor, int active_bgcolor, int inactive_bgcolor, int active_fgcolor, int inactive_fgcolor, int framecolor, int sepcolor, ...);
/**
* Set the help URL for the given window.
*
* @param window The window.
* @param help_url String containing URL of the help page for this
* window, or NULL to set no help for this window.
*/
void TXT_SetWindowHelpURL(txt_window_t *window, const char *help_url);
/**
* Open the help URL for the given window, if one is set.
*
* @param window The window.
*/
void TXT_OpenWindowHelpURL(txt_window_t *window);
#endif /* #ifndef TXT_WINDOW_H */
@@ -0,0 +1,173 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "doomkeys.h"
#include "txt_window_action.h"
#include "txt_gui.h"
#include "txt_io.h"
#include "txt_main.h"
#include "txt_utf8.h"
#include "txt_window.h"
#ifdef _MSC_VER
#define strdup _strdup
#endif
static void TXT_WindowActionSizeCalc(TXT_UNCAST_ARG(action))
{
TXT_CAST_ARG(txt_window_action_t, action);
char buf[10];
TXT_GetKeyDescription(action->key, buf, sizeof(buf));
// Width is label length, plus key description length, plus '='
// and two surrounding spaces.
action->widget.w = TXT_UTF8_Strlen(action->label)
+ TXT_UTF8_Strlen(buf) + 3;
action->widget.h = 1;
}
static void TXT_WindowActionDrawer(TXT_UNCAST_ARG(action))
{
TXT_CAST_ARG(txt_window_action_t, action);
int hovering;
char buf[10];
TXT_GetKeyDescription(action->key, buf, sizeof(buf));
hovering = TXT_HoveringOverWidget(action);
TXT_SetWidgetBG(action);
TXT_DrawString(" ");
TXT_FGColor(hovering ? TXT_COLOR_BRIGHT_WHITE : TXT_COLOR_BRIGHT_GREEN);
TXT_DrawString(buf);
TXT_FGColor(TXT_COLOR_BRIGHT_CYAN);
TXT_DrawString("=");
TXT_FGColor(TXT_COLOR_BRIGHT_WHITE);
TXT_DrawString(action->label);
TXT_DrawString(" ");
}
static void TXT_WindowActionDestructor(TXT_UNCAST_ARG(action))
{
TXT_CAST_ARG(txt_window_action_t, action);
free(action->label);
}
static int TXT_WindowActionKeyPress(TXT_UNCAST_ARG(action), int key)
{
TXT_CAST_ARG(txt_window_action_t, action);
if (tolower(key) == tolower(action->key))
{
TXT_EmitSignal(action, "pressed");
return 1;
}
return 0;
}
static void TXT_WindowActionMousePress(TXT_UNCAST_ARG(action),
int x, int y, int b)
{
TXT_CAST_ARG(txt_window_action_t, action);
// Simulate a press of the key
if (b == TXT_MOUSE_LEFT)
{
TXT_WindowActionKeyPress(action, action->key);
}
}
txt_widget_class_t txt_window_action_class =
{
TXT_AlwaysSelectable,
TXT_WindowActionSizeCalc,
TXT_WindowActionDrawer,
TXT_WindowActionKeyPress,
TXT_WindowActionDestructor,
TXT_WindowActionMousePress,
NULL,
};
txt_window_action_t *TXT_NewWindowAction(int key, const char *label)
{
txt_window_action_t *action;
action = malloc(sizeof(txt_window_action_t));
TXT_InitWidget(action, &txt_window_action_class);
action->key = key;
action->label = strdup(label);
return action;
}
static void WindowCloseCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(window))
{
TXT_CAST_ARG(txt_window_t, window);
TXT_CloseWindow(window);
}
static void WindowSelectCallback(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(window))
{
TXT_CAST_ARG(txt_window_t, window);
TXT_WidgetKeyPress(window, KEY_ENTER);
}
// An action with the name "close" the closes the window
txt_window_action_t *TXT_NewWindowEscapeAction(txt_window_t *window)
{
txt_window_action_t *action;
action = TXT_NewWindowAction(KEY_ESCAPE, "Close");
TXT_SignalConnect(action, "pressed", WindowCloseCallback, window);
return action;
}
// Exactly the same as the above, but the button is named "abort"
txt_window_action_t *TXT_NewWindowAbortAction(txt_window_t *window)
{
txt_window_action_t *action;
action = TXT_NewWindowAction(KEY_ESCAPE, "Abort");
TXT_SignalConnect(action, "pressed", WindowCloseCallback, window);
return action;
}
txt_window_action_t *TXT_NewWindowSelectAction(txt_window_t *window)
{
txt_window_action_t *action;
action = TXT_NewWindowAction(KEY_ENTER, "Select");
TXT_SignalConnect(action, "pressed", WindowSelectCallback, window);
return action;
}
@@ -0,0 +1,89 @@
//
// Copyright(C) 2005-2014 Simon Howard
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
#ifndef TXT_WINDOW_ACTION_H
#define TXT_WINDOW_ACTION_H
/**
* @file txt_window_action.h
*
* Window action widget.
*/
/**
* Window action widget.
*
* A window action is attached to a window and corresponds to a
* keyboard shortcut that is active within that window. When the
* key is pressed, the action is triggered.
*
* When a window action is triggered, the "pressed" signal is emitted.
*/
typedef struct txt_window_action_s txt_window_action_t;
#include "txt_widget.h"
#include "txt_window.h"
struct txt_window_action_s
{
txt_widget_t widget;
char *label;
int key;
};
/**
* Create a new window action.
*
* @param key The keyboard key that triggers this action.
* @param label Label to display for this action in the tray
* at the bottom of the window (UTF-8 format).
* @return Pointer to the new window action widget.
*/
txt_window_action_t *TXT_NewWindowAction(int key, const char *label);
/**
* Create a new window action that closes the window when the
* escape key is pressed. The label "Close" is used.
*
* @param window The window to close.
* @return Pointer to the new window action widget.
*/
txt_window_action_t *TXT_NewWindowEscapeAction(txt_window_t *window);
/**
* Create a new window action that closes the window when the
* escape key is pressed. The label "Abort" is used.
*
* @param window The window to close.
* @return Pointer to the new window action widget.
*/
txt_window_action_t *TXT_NewWindowAbortAction(txt_window_t *window);
/**
* Create a new "select" window action. This does not really do
* anything, but reminds the user that "enter" can be pressed to
* activate the currently-selected widget.
*
* @param window The window.
* @return Pointer to the new window action widget.
*/
txt_window_action_t *TXT_NewWindowSelectAction(txt_window_t *window);
#endif /* #ifndef TXT_WINDOW_ACTION_H */
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,31 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31205.134
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "textscreen", "textscreen.vcxproj", "{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Debug|x64.ActiveCfg = Debug|x64
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Debug|x64.Build.0 = Debug|x64
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Debug|x86.ActiveCfg = Debug|Win32
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Debug|x86.Build.0 = Debug|Win32
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Release|x64.ActiveCfg = Release|x64
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Release|x64.Build.0 = Release|x64
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Release|x86.ActiveCfg = Release|Win32
{137BAB62-5A11-4928-93F7-BA5DF69BEEE2}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {246E79C8-8023-40CF-9E27-4A61BAE7F450}
EndGlobalSection
EndGlobal
@@ -0,0 +1,208 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\include\txt_button.c" />
<ClCompile Include="..\include\txt_checkbox.c" />
<ClCompile Include="..\include\txt_conditional.c" />
<ClCompile Include="..\include\txt_desktop.c" />
<ClCompile Include="..\include\txt_dropdown.c" />
<ClCompile Include="..\include\txt_fileselect.c" />
<ClCompile Include="..\include\txt_gui.c" />
<ClCompile Include="..\include\txt_inputbox.c" />
<ClCompile Include="..\include\txt_io.c" />
<ClCompile Include="..\include\txt_label.c" />
<ClCompile Include="..\include\txt_radiobutton.c" />
<ClCompile Include="..\include\txt_scrollpane.c" />
<ClCompile Include="..\include\txt_sdl.c" />
<ClCompile Include="..\include\txt_separator.c" />
<ClCompile Include="..\include\txt_spinctrl.c" />
<ClCompile Include="..\include\txt_strut.c" />
<ClCompile Include="..\include\txt_table.c" />
<ClCompile Include="..\include\txt_utf8.c" />
<ClCompile Include="..\include\txt_widget.c" />
<ClCompile Include="..\include\txt_window.c" />
<ClCompile Include="..\include\txt_window_action.c" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\doomkeys.h" />
<ClInclude Include="..\include\textscreen.h" />
<ClInclude Include="..\include\txt_button.h" />
<ClInclude Include="..\include\txt_checkbox.h" />
<ClInclude Include="..\include\txt_conditional.h" />
<ClInclude Include="..\include\txt_desktop.h" />
<ClInclude Include="..\include\txt_dropdown.h" />
<ClInclude Include="..\include\txt_fileselect.h" />
<ClInclude Include="..\include\txt_gui.h" />
<ClInclude Include="..\include\txt_inputbox.h" />
<ClInclude Include="..\include\txt_io.h" />
<ClInclude Include="..\include\txt_label.h" />
<ClInclude Include="..\include\txt_main.h" />
<ClInclude Include="..\include\txt_radiobutton.h" />
<ClInclude Include="..\include\txt_scrollpane.h" />
<ClInclude Include="..\include\txt_sdl.h" />
<ClInclude Include="..\include\txt_separator.h" />
<ClInclude Include="..\include\txt_spinctrl.h" />
<ClInclude Include="..\include\txt_strut.h" />
<ClInclude Include="..\include\txt_table.h" />
<ClInclude Include="..\include\txt_utf8.h" />
<ClInclude Include="..\include\txt_widget.h" />
<ClInclude Include="..\include\txt_window.h" />
<ClInclude Include="..\include\txt_window_action.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{137bab62-5a11-4928-93f7-ba5df69beee2}</ProjectGuid>
<RootNamespace>textscreen</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>StaticLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\..\SDL2-devel-2.28.2-VC\SDL2-2.28.2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\Users\Skynet\source\libs\SDL2-devel-2.0.14-VC\SDL2-2.0.14\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2main.lib;SDL2.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\..\SDL2-devel-2.28.2-VC\SDL2-2.28.2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\Users\Skynet\source\libs\SDL2-devel-2.0.14-VC\SDL2-2.0.14\lib\x86;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2main.lib;SDL2.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\..\SDL2-devel-2.28.2-VC\SDL2-2.28.2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<DebugInformationFormat>OldStyle</DebugInformationFormat>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\Users\Skynet\Downloads\github\raptor-master32bit\include\SDL2-devel-2.0.14-VC\SDL2-2.0.14\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<AdditionalIncludeDirectories>..\..\SDL2-devel-2.28.2-VC\SDL2-2.28.2\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalLibraryDirectories>C:\Users\Skynet\Downloads\github\raptor-master32bit\include\SDL2-devel-2.0.14-VC\SDL2-2.0.14\lib\x64;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Quelldateien">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Ressourcendateien">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Headerdateien">
<UniqueIdentifier>{53e021b0-f051-4ee2-a730-80bf8e0ecb1a}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="..\include\txt_button.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_checkbox.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_conditional.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_desktop.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_dropdown.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_fileselect.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_gui.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_inputbox.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_io.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_label.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_radiobutton.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_scrollpane.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_sdl.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_separator.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_spinctrl.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_strut.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_table.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_utf8.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_widget.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_window.c">
<Filter>Quelldateien</Filter>
</ClCompile>
<ClCompile Include="..\include\txt_window_action.c">
<Filter>Quelldateien</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\include\doomkeys.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\textscreen.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_button.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_checkbox.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_conditional.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_desktop.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_dropdown.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_fileselect.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_gui.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_inputbox.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_io.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_label.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_main.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_radiobutton.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_scrollpane.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_sdl.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_separator.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_spinctrl.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_strut.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_table.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_utf8.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_widget.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_window.h">
<Filter>Headerdateien</Filter>
</ClInclude>
<ClInclude Include="..\include\txt_window_action.h">
<Filter>Headerdateien</Filter>
</ClInclude>
</ItemGroup>
</Project>
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup />
</Project>