Got an intial console working, at least for simple typing.
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
#ifndef TSTRING_H
|
||||
#define TSTRING_H
|
||||
|
||||
#ifndef DEFAULT_TSTRING_BYTE_BUFFER
|
||||
#define DEFAULT_TSTRING_BYTE_BUFFER 32
|
||||
#endif
|
||||
|
||||
typedef struct tstring TString;
|
||||
|
||||
TString* TStringCreate(void);
|
||||
void TStringTruncate(TString* string);
|
||||
void TStringAppendText(const char* text, TString* string);
|
||||
void TStringGetGlyph(int index, char buffer[8], const TString* string);
|
||||
void TStringFree(TString* string);
|
||||
void TStringPrintDetails(const TString* string, int statsOnly);
|
||||
void TStringInsertText(const char* text, int index, TString* string);
|
||||
void TStringPop(char buffer[8], TString* string);
|
||||
void TStringRemoveRange(int startIndex, int count, TString* string);
|
||||
void TStringGetStringRange(const TString* string, unsigned int startIndex, unsigned int count, unsigned int bufferSize, char buffer[]);
|
||||
char* TStringGetString(const TString* string);
|
||||
int TStringLength(const TString* string);
|
||||
|
||||
|
||||
#endif
|
||||
+89
-22
@@ -1,7 +1,15 @@
|
||||
#include <SDL2/SDL_events.h>
|
||||
#include <SDL2/SDL_pixels.h>
|
||||
#include <SDL2/SDL_rect.h>
|
||||
#include <SDL2/SDL_render.h>
|
||||
#include <SDL2/SDL_stdinc.h>
|
||||
#include <SDL2/SDL_surface.h>
|
||||
#include <stdio.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_mouse.h>
|
||||
#include <SDL2/SDL_ttf.h>
|
||||
#include <inttypes.h>
|
||||
#include "../includes/tstring.h"
|
||||
|
||||
int Exit = 0;
|
||||
int XRel = 0, YRel = 0;
|
||||
@@ -10,18 +18,25 @@ int XOrg = 0, YOrg = 0;
|
||||
typedef struct {
|
||||
SDL_Window *window;
|
||||
SDL_Renderer *renderer;
|
||||
unsigned short DefaultFontSize;
|
||||
TTF_Font* DefaultFont;
|
||||
} Client;
|
||||
|
||||
Client app;
|
||||
const int SCREEN_WIDTH = 1280;
|
||||
const int SCREEN_HEIGHT = 720;
|
||||
const int SCREEN_WIDTH = 100;
|
||||
const int SCREEN_HEIGHT = 600;
|
||||
Uint32 KeyPress;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
SDL_Rect FontSize;
|
||||
TString* TextBuffer;
|
||||
|
||||
void HandleInput(void);
|
||||
void NewLine(void);
|
||||
void Cleanup(void);
|
||||
|
||||
int main(int argc, char** argv){
|
||||
memset(&app, 0, sizeof(app));
|
||||
TextBuffer = TStringCreate();
|
||||
|
||||
atexit(Cleanup);
|
||||
|
||||
@@ -41,6 +56,16 @@ int main(int argc, char** argv){
|
||||
return -1;
|
||||
}
|
||||
|
||||
TTF_Init();
|
||||
|
||||
app.DefaultFont = TTF_OpenFont("/usr/share/fonts/TTF/Hack-Regular.ttf", 26);
|
||||
|
||||
TTF_SizeUTF8(app.DefaultFont, "A", &FontSize.w, &FontSize.h);
|
||||
|
||||
int chars = SCREEN_WIDTH / FontSize.w;
|
||||
|
||||
printf("Chars per line: %d\n", chars);
|
||||
|
||||
while(!Exit) {
|
||||
SDL_Delay(16);
|
||||
|
||||
@@ -50,13 +75,57 @@ int main(int argc, char** argv){
|
||||
|
||||
SDL_RenderClear(app.renderer);
|
||||
|
||||
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 0);
|
||||
|
||||
FontSize.x = FontSize.w * x;
|
||||
|
||||
if (FontSize.x + FontSize.w > SCREEN_WIDTH){
|
||||
x = 0;
|
||||
FontSize.x = 0;
|
||||
|
||||
NewLine();
|
||||
}
|
||||
|
||||
SDL_Color white = {255, 255, 255};
|
||||
|
||||
for(int i = 0; i < TStringLength(TextBuffer); i++) {
|
||||
SDL_Rect Message_rect; //create a rect
|
||||
Message_rect.x = i % chars * FontSize.w; //controls the rect's x coordinate
|
||||
Message_rect.y = i / chars * FontSize.h; // controls the rect's y coordinte
|
||||
Message_rect.w = FontSize.w; // controls the width of the rect
|
||||
Message_rect.h = FontSize.h; // controls the height of the rect
|
||||
|
||||
char buffer[8];
|
||||
TStringGetGlyph(i, buffer, TextBuffer);
|
||||
SDL_Surface* sur = TTF_RenderText_Solid(app.DefaultFont, buffer, white);
|
||||
SDL_Texture* Message = SDL_CreateTextureFromSurface(app.renderer, sur);
|
||||
|
||||
SDL_RenderCopy(app.renderer, Message, NULL, &Message_rect);
|
||||
|
||||
SDL_FreeSurface(sur);
|
||||
SDL_DestroyTexture(Message);
|
||||
}
|
||||
|
||||
FontSize.y = y * FontSize.h;
|
||||
|
||||
SDL_RenderDrawRect(app.renderer, &FontSize);
|
||||
|
||||
SDL_RenderPresent(app.renderer);
|
||||
}
|
||||
}
|
||||
|
||||
void NewLine(void) {
|
||||
x = 0;
|
||||
|
||||
if (FontSize.h * (y + 2) > SCREEN_HEIGHT) return;
|
||||
|
||||
y++;
|
||||
}
|
||||
|
||||
void Cleanup(void) {
|
||||
SDL_DestroyWindow(app.window);
|
||||
SDL_DestroyRenderer(app.renderer);
|
||||
TTF_CloseFont(app.DefaultFont);
|
||||
TTF_Quit();
|
||||
SDL_Quit();
|
||||
}
|
||||
@@ -68,26 +137,24 @@ void HandleInput(void) {
|
||||
case SDL_QUIT:
|
||||
Exit = 1;
|
||||
break;
|
||||
// case SDL_MOUSEBUTTONDOWN:
|
||||
// if (event.button.button == SDL_BUTTON_RIGHT) Exit = 1;
|
||||
// MouseDown = 1;
|
||||
// break;
|
||||
// case SDL_MOUSEBUTTONUP:
|
||||
// MouseDown = 0;
|
||||
// break;
|
||||
// case SDL_MOUSEMOTION:
|
||||
// //if (MainMenu->HitCheck(event.motion.x, event.motion.y, &MainMenu->Area)) {
|
||||
// if (MouseDown){
|
||||
// XRel += event.motion.xrel;
|
||||
// YRel += event.motion.yrel;
|
||||
// }
|
||||
// break;
|
||||
// case SDL_MOUSEWHEEL:
|
||||
// if (event.wheel.y > 0 && ZoomLevel < 2) ZoomLevel += .05;
|
||||
// else if (event.wheel.y < 0 && ZoomLevel > 0.25) ZoomLevel -= .05;
|
||||
// break;
|
||||
case SDL_KEYUP:
|
||||
if (event.key.keysym.scancode == SDL_SCANCODE_BACKSPACE)
|
||||
{
|
||||
if (x == 0 && y > 0)
|
||||
{
|
||||
x = SCREEN_WIDTH / FontSize.w - 1;
|
||||
y--;
|
||||
}
|
||||
else if (x > 0) x--;
|
||||
|
||||
TStringPop(NULL, TextBuffer);
|
||||
|
||||
printf("String: '%s'\n", TStringGetString(TextBuffer));
|
||||
}
|
||||
break;
|
||||
case SDL_TEXTINPUT:
|
||||
case SDL_KEYDOWN:
|
||||
x++;
|
||||
TStringAppendText(event.text.text, TextBuffer);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+328
@@ -0,0 +1,328 @@
|
||||
#include "../includes/tstring.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
void TStringCopyGlyph(const char* glyph, int length, TString* string);
|
||||
int ResizeTStringCapacity(int newTextLength, TString* string);
|
||||
int GetGlyphByteWidth(char glyph);
|
||||
|
||||
struct tstring {
|
||||
char* Characters;
|
||||
int Length;
|
||||
int ByteCount;
|
||||
int Capacity;
|
||||
};
|
||||
|
||||
TString* TStringCreate(void) {
|
||||
TString* string = malloc(sizeof(TString));
|
||||
|
||||
if (!string) {
|
||||
fprintf(stderr, "Failed to malloc space for TString. %s.\n", strerror(errno));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string->Characters = calloc(DEFAULT_TSTRING_BYTE_BUFFER, sizeof(char));
|
||||
|
||||
if (!string->Characters) {
|
||||
fprintf(stderr, "Failed to malloc space for TString character array. %s.\n", strerror(errno));
|
||||
|
||||
free(string);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
string->Capacity = DEFAULT_TSTRING_BYTE_BUFFER;
|
||||
string->ByteCount = 0;
|
||||
string->Length = 0;
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
void TStringTruncate(TString* string) {
|
||||
if (!string) return;
|
||||
|
||||
char* newBuffer = calloc(DEFAULT_TSTRING_BYTE_BUFFER, sizeof(char));
|
||||
|
||||
if (!newBuffer) {
|
||||
fprintf(stderr, "Failed to calloc space during TString truncation. %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
free(string->Characters);
|
||||
|
||||
string->Characters = newBuffer;
|
||||
string->Capacity = DEFAULT_TSTRING_BYTE_BUFFER;
|
||||
string->ByteCount = 0;
|
||||
string->Length = 0;
|
||||
}
|
||||
|
||||
int TStringLength(const TString* string) {
|
||||
if (!string) return -1;
|
||||
|
||||
return string->Length;
|
||||
}
|
||||
|
||||
int ResizeTStringCapacity(int additionalLength, TString* string) {
|
||||
if (!string) return 0;
|
||||
if (string->ByteCount + additionalLength < string->Capacity) return 1;
|
||||
|
||||
unsigned int newCapacity = string->Capacity;
|
||||
|
||||
while (additionalLength > newCapacity) newCapacity = string->Capacity * 2;
|
||||
|
||||
char* buffer = realloc(string->Characters, string->Capacity * 2);
|
||||
|
||||
if (!buffer) {
|
||||
fprintf(stderr, "Failed to realloc space for text insertion. %s.\n", strerror(errno));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
string->Characters = buffer;
|
||||
string->Capacity *= 2;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void TStringPop(char buffer[8], TString* string) {
|
||||
if (!string) return;
|
||||
if (string->ByteCount == 0) return;
|
||||
|
||||
for (int i = string->ByteCount - 1; i >= 0; i--) {
|
||||
unsigned int width = GetGlyphByteWidth(string->Characters[i]);
|
||||
|
||||
if (width > 0) {
|
||||
//If we've been provided a buffer, then populate it with the glyph we're removing.
|
||||
if (buffer) {
|
||||
memset(buffer, '\0', 8);
|
||||
memcpy(buffer, &string->Characters[i], width);
|
||||
}
|
||||
|
||||
memset(&string->Characters[i], '\0', width);
|
||||
string->Length--;
|
||||
string->ByteCount -= width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TStringRemoveRange(int startIndex, int count, TString* string) {
|
||||
if (!string) return;
|
||||
if (startIndex < 0 || startIndex > string->Length) return;
|
||||
if (count <= 0 || count > string->Length - startIndex) return;
|
||||
|
||||
char buffer[256] = { 0 };
|
||||
unsigned int startByte = 0;
|
||||
unsigned int glyphCount = 0;
|
||||
|
||||
while(glyphCount != startIndex) {
|
||||
startByte += GetGlyphByteWidth(string->Characters[startByte]);
|
||||
|
||||
glyphCount++;
|
||||
}
|
||||
|
||||
unsigned int endByte = startByte;
|
||||
|
||||
for (glyphCount = 0; glyphCount < count; glyphCount++) endByte += GetGlyphByteWidth(string->Characters[endByte]);
|
||||
|
||||
unsigned int fullBuffers = (string->ByteCount - endByte) / sizeof buffer;
|
||||
unsigned int remainder = (string->ByteCount - endByte) - fullBuffers * sizeof buffer;
|
||||
|
||||
for (int i = 0; i < fullBuffers; i++) {
|
||||
memcpy(buffer, &string->Characters[endByte + i * sizeof buffer], sizeof buffer);
|
||||
memcpy(&string->Characters[startByte + sizeof buffer * i], buffer, sizeof buffer);
|
||||
}
|
||||
|
||||
if (remainder > 0) {
|
||||
memset(buffer, 0, sizeof buffer);
|
||||
memcpy(buffer, &string->Characters[string->ByteCount - remainder], remainder);
|
||||
memcpy(&string->Characters[startByte + fullBuffers * sizeof buffer], buffer, remainder);
|
||||
}
|
||||
|
||||
string->Length -= glyphCount;
|
||||
string->ByteCount -= endByte - startByte;
|
||||
|
||||
memset(&string->Characters[string->ByteCount], '\0', string->Capacity - string->ByteCount);
|
||||
}
|
||||
|
||||
void TStringInsertText(const char* text, int index, TString* string) {
|
||||
if (!text || !string) return;
|
||||
if (index < 0 || index > string->Length) index = string->Length;
|
||||
|
||||
unsigned int insertionTextLength = strlen(text);
|
||||
unsigned int startByte = 0;
|
||||
unsigned int endByte = string->ByteCount + insertionTextLength;
|
||||
|
||||
if (!ResizeTStringCapacity(insertionTextLength, string)) return;
|
||||
|
||||
char buffer[256] = { 0 };
|
||||
|
||||
for (int glyphCount = 0; glyphCount != index; glyphCount++) startByte += GetGlyphByteWidth(string->Characters[startByte]);
|
||||
for (unsigned int offset = 0; offset < insertionTextLength; string->Length++) offset += GetGlyphByteWidth(text[offset]);
|
||||
|
||||
unsigned int fullBuffers = (string->ByteCount - startByte) / sizeof buffer;
|
||||
unsigned int remainder = (string->ByteCount - startByte) - fullBuffers * sizeof buffer;
|
||||
|
||||
for (int i = fullBuffers; i > 0; i--) {
|
||||
memcpy(buffer, &string->Characters[string->ByteCount - i * sizeof buffer], sizeof buffer);
|
||||
memcpy(&string->Characters[endByte - sizeof buffer * i], buffer, sizeof buffer);
|
||||
}
|
||||
|
||||
if (remainder > 0) {
|
||||
memcpy(buffer, &string->Characters[startByte], remainder);
|
||||
memcpy(&string->Characters[insertionTextLength + startByte], buffer, remainder);
|
||||
}
|
||||
|
||||
memcpy(&string->Characters[startByte], text, insertionTextLength);
|
||||
|
||||
string->ByteCount += insertionTextLength;
|
||||
}
|
||||
|
||||
void TStringAppendText(const char* text, TString* string) {
|
||||
if (!text || !string) return;
|
||||
|
||||
int totalLength = strlen(text);
|
||||
int glyphLength = GetGlyphByteWidth(text[0]);
|
||||
|
||||
//If the two lengths are the same then that means we have a single character.
|
||||
//Simply append it to the list and return.
|
||||
if (totalLength == glyphLength) {
|
||||
TStringCopyGlyph(text, glyphLength, string);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//If we've made it here, than that means we have a full on string of characters.
|
||||
for(int i = 0; i < totalLength;) {
|
||||
TStringCopyGlyph(&text[i], glyphLength, string);
|
||||
|
||||
i += glyphLength;
|
||||
glyphLength = GetGlyphByteWidth(text[i]);
|
||||
}
|
||||
}
|
||||
|
||||
char* TStringGetString(const TString* string) {
|
||||
if (!string) return NULL;
|
||||
|
||||
char* text = calloc(string->ByteCount + 1, sizeof(char));
|
||||
|
||||
if (!text) {
|
||||
fprintf(stderr, "Failed to calloc memory for TString text. %s.\n", strerror(errno));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(text, string->Characters, string->ByteCount);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
void TStringGetStringRange(const TString* string, unsigned int startIndex, unsigned int count, unsigned int bufferSize, char buffer[]) {
|
||||
if (!string || !buffer) return;
|
||||
if (count > string->Length) return;
|
||||
|
||||
unsigned int glyphCount = 0, startByte = 0;
|
||||
|
||||
while (glyphCount != startIndex) {
|
||||
startByte += GetGlyphByteWidth(string->Characters[startByte]);
|
||||
|
||||
glyphCount++;
|
||||
}
|
||||
|
||||
unsigned int endByte = startByte;
|
||||
|
||||
for(glyphCount = 0; glyphCount < count && endByte <= string->ByteCount && endByte - startByte < bufferSize; glyphCount++) {
|
||||
int width = GetGlyphByteWidth(string->Characters[endByte]);
|
||||
|
||||
if (width + endByte - startByte < bufferSize) endByte += width;
|
||||
else break;
|
||||
}
|
||||
|
||||
memset(buffer, 0, bufferSize);
|
||||
memcpy(buffer, &string->Characters[startByte], endByte - startByte);
|
||||
}
|
||||
|
||||
void TStringGetGlyph(int index, char buffer[8], const TString* string) {
|
||||
if (!buffer || !string) return;
|
||||
if (index > TStringLength(string)) return;
|
||||
|
||||
memset(buffer, '\0', sizeof *buffer);
|
||||
|
||||
int glyphCount = 0;
|
||||
|
||||
for (int i = 0; i < string->ByteCount;) {
|
||||
int glyphWidth = GetGlyphByteWidth(string->Characters[i]);
|
||||
|
||||
if (glyphCount == index) {
|
||||
memcpy(buffer, &string->Characters[i], glyphWidth);
|
||||
return;
|
||||
}
|
||||
|
||||
glyphCount++;
|
||||
i += glyphWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void TStringFree(TString* string) {
|
||||
if (!string) return;
|
||||
|
||||
if (string->Characters) free(string->Characters);
|
||||
|
||||
free(string);
|
||||
}
|
||||
|
||||
int GetGlyphByteWidth(char glyph) {
|
||||
//ANDing 0x80 (1000 0000) should result in 0 if this code point is 1 byte long.
|
||||
if ((glyph & 0x80) == 0) return 1;
|
||||
|
||||
//ANDing 0xE0 (1110 0000) will result in 0xC0 (1100 0000) if this code point is 2 bytes long.
|
||||
if ((glyph & 0xE0) == 0xC0) return 2;
|
||||
|
||||
//ANDing 0xF0 (1111 0000) will result in 0xE0 (1110 0000) if this code point is 3 bytes long.
|
||||
if ((glyph & 0xF0) == 0xE0) return 3;
|
||||
|
||||
//ANDing 0xE0 (1111 1000) will result in 0xF0 (1111 0000) if this code point is 4 bytes long.
|
||||
if ((glyph & 0xF8) == 0xF0) return 4;
|
||||
|
||||
//Else we either have a continuation point (pattern: 10XX XXXX) or its just a junk value
|
||||
//as far as we're concerned.
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TStringCopyGlyph(const char* glyph, int length, TString* string) {
|
||||
if (!glyph || !string) return;
|
||||
if (length < 1) return;
|
||||
|
||||
if (!ResizeTStringCapacity(length, string)) return;
|
||||
|
||||
memcpy(&string->Characters[string->ByteCount], glyph, length);
|
||||
|
||||
string->ByteCount += length;
|
||||
string->Length++;
|
||||
}
|
||||
|
||||
void TStringPrintDetails(const TString* string, int statsOnly) {
|
||||
if (!string) return;
|
||||
|
||||
printf("Stats: Length %d; Size %d byte(s); Capacity: %d bytes\n", string->Length, string->ByteCount, string->Capacity);
|
||||
|
||||
if (statsOnly) return;
|
||||
|
||||
printf("Stored String:\n");
|
||||
|
||||
if (string->Characters) {
|
||||
char* text = TStringGetString(string);
|
||||
printf("%s\n", text);
|
||||
free(text);
|
||||
}
|
||||
|
||||
printf("\nBytes:\n");
|
||||
for(int i = 0; i < string->Capacity; i++) {
|
||||
if (i != 0 && i % 80 == 0) printf("\n");
|
||||
printf("%02X ", string->Characters[i] & 0xFF);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
Reference in New Issue
Block a user