minor perf improvement regarding chat list hovers, code cleanup, cut first release candidate

This commit is contained in:
camh 2022-02-18 23:46:29 -08:00
parent 695093d0bf
commit 0c16aa46ba
6 changed files with 92 additions and 164 deletions

View File

@ -83,7 +83,7 @@ void setupPBControlForSerialPort(short serialPortShort) {
CntrlParam cb;
cb.ioCRefNum = serialPortShort; // TODO: this is always 0 - does it matter? should we hard code 0 here? research
cb.csCode = 8; // TODO: need to look up and document what csCode = 8 means
cb.csParam[0] = stop10 | noParity | data8 | baud28800; // TODO: can we achieve higher than 9600 baud? - should be able to achieve at least 19.2k on a 68k machine
cb.csParam[0] = stop10 | noParity | data8 | baud28800; // 28.8k has been pretty reliable on my Macintosh Classic...
OSErr err = PBControl ((ParmBlkPtr) & cb, 0); // PBControl definition: http://mirror.informatimago.com/next/developer.apple.com/documentation/mac/Networking/Networking-296.html
#ifdef PRINT_ERRORS
@ -235,7 +235,9 @@ void readSerialPort(char* output) {
while (!done) {
if (loopCounter++ > MAX_RECIEVE_LOOP_ITERATIONS) {
writeSerialPortDebug(boutRefNum, "coprocessor.readSerialPort MAX RECEIVE ITERATIONS");
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "coprocessor.readSerialPort MAX RECEIVE ITERATIONS");
#endif
char *errorMessage = "TIMEOUT_ERROR";
@ -343,8 +345,10 @@ void readSerialPort(char* output) {
// attach the gathered up output from the buffer to the output variable
strncat(output, tempOutput, totalByteCount);
writeSerialPortDebug(boutRefNum, "coprocessor.readSerialPort complete, output:");
writeSerialPortDebug(boutRefNum, output);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "coprocessor.readSerialPort complete, output:");
writeSerialPortDebug(boutRefNum, output);
#endif
// once we are done reading the buffer entirely, we need to clear it. i'm not sure if this is the best way or not but seems to work
memset(GlobalSerialInputBuffer, '\0', MAX_RECEIVE_SIZE);
@ -364,7 +368,7 @@ OSErr writeSerialPort(const char* stringToWrite) {
printf("writeSerialPort\n");
#endif
outgoingSerialPortReference.ioBuffer = (Ptr) stringToWrite;
outgoingSerialPortReference.ioBuffer = (Ptr)stringToWrite;
outgoingSerialPortReference.ioReqCount = strlen(stringToWrite);
#ifdef DEBUGGING
@ -510,7 +514,10 @@ char* _getReturnValueFromResponse(char* response, char* application_id, char* ca
// writeSerialPortDebug(boutRefNum, x);
sprintf(output, "%.*s", lengthWithoutControlChars, token); // drop the ;;@@&& off the end of the response
writeSerialPortDebug(boutRefNum, output);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, output);
#endif
return NULL;
@ -594,7 +601,6 @@ void getReturnValueFromResponse(char *response, char *operation, char *output) {
#endif
}
// TODO: this is a function we would want to expose in a library
// TODO: these should all bubble up and return legible errors
void sendProgramToCoprocessor(char* program, char *output) {
@ -621,7 +627,6 @@ void sendProgramToCoprocessor(char* program, char *output) {
return;
}
// TODO: this is a function we would want to expose in a library
void callFunctionOnCoprocessor(char* functionName, char* parameters, char* output) {
#ifdef DEBUG_FUNCTION_CALLS
@ -643,33 +648,41 @@ void callFunctionOnCoprocessor(char* functionName, char* parameters, char* outpu
sprintf(functionCallMessage, functionTemplate, functionName, parameters);
SetCursor(*GetCursor(watchCursor));
// writeSerialPortDebug(boutRefNum, functionCallMessage);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, functionCallMessage);
#endif
writeToCoprocessor("FUNCTION", functionCallMessage);
char serialPortResponse[MAX_RECEIVE_SIZE];
readSerialPort(serialPortResponse);
writeSerialPortDebug(boutRefNum, "========================Got response from serial port");
writeSerialPortDebug(boutRefNum, serialPortResponse);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "Got response from serial port:");
writeSerialPortDebug(boutRefNum, serialPortResponse);
#endif
memset(output, '\0', RECEIVE_WINDOW_SIZE);
getReturnValueFromResponse(serialPortResponse, "FUNCTION", output);
writeSerialPortDebug(boutRefNum, "========================and return value from response");
writeSerialPortDebug(boutRefNum, output);
#ifdef DEBUGGING
writeSerialPortDebug(boutRefNum, "Greturn value from response");
writeSerialPortDebug(boutRefNum, output);
#endif
SetCursor(&qd.arrow);
return;
}
// TODO: this is a function we would want to expose in a library
void callEvalOnCoprocessor(char* toEval, char* output) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: callEvalOnCoprocessor");
#endif
#ifdef DEBUGGING
printf("callEvalOnCoprocessor\n");
#endif

Binary file not shown.

Binary file not shown.

View File

@ -215,7 +215,7 @@ void EventLoop(struct nk_context *ctx)
// this should be out of sync with the counter above it so that we dont end up making
// two coprocessor calls on one event loop iteratio
if (TickCount() - lastUpdatedTickCountChatCounts > 600) {
if (TickCount() - lastUpdatedTickCountChatCounts > 500) {
// writeSerialPortDebug(boutRefNum, "update by tick count");
lastUpdatedTickCountChatCounts = TickCount();
@ -313,7 +313,7 @@ void EventLoop(struct nk_context *ctx)
SystemTask();
// only re-render if there is an event, prevents screen flickering, speeds up app
if (beganInput || firstOrMouseMove || forceRedraw) {
if (beganInput || firstOrMouseMove || forceRedrawChats || forceRedrawMessages) {
#ifdef PROFILING
PROFILE_START("nk_input_end");
@ -344,7 +344,7 @@ void EventLoop(struct nk_context *ctx)
writeSerialPortDebug(boutRefNum, "nk_quickdraw_render");
char x[255];
sprintf(x, "why? beganInput: %d, firstOrMouseMove: %d, forceRedraw: %d", beganInput, firstOrMouseMove, forceRedraw);
sprintf(x, "why? beganInput: %d, firstOrMouseMove: %d, forceRedraw: %d", beganInput, firstOrMouseMove, forceRedrawChats);
writeSerialPortDebug(boutRefNum, x);
#endif
@ -401,8 +401,7 @@ void DoEvent(EventRecord *event, struct nk_context *ctx) {
#endif
part = FindWindow(event->where, &window);
switch (part)
{
switch (part) {
case inContent:
nk_quickdraw_handle_event(event, ctx);
break;

View File

@ -1,6 +1,3 @@
// TODO:
// - test on physical, bug fixes, write blog posts
// {42, 4, 336, 506}
#define WINDOW_WIDTH 502
#define WINDOW_HEIGHT 294
@ -99,7 +96,7 @@ void aFailed(char *file, int line) {
}
#define MAX_CHAT_MESSAGES 17
#define MAX_RECEIVE_SIZE 32767
#define MAX_RECEIVE_SIZE 32767 // this has a corresponding value in coprocessor.c
Boolean firstOrMouseMove = true;
Boolean gotMouseEvent = false;
@ -108,15 +105,16 @@ char activeChatMessages[MAX_CHAT_MESSAGES][2048]; // this should match to MAX_RO
char box_input_buffer[2048];
char chatFriendlyNames[16][64];
char ip_input_buffer[255];
char jsFunctionResponse[MAX_RECEIVE_SIZE]; // Matches MAX_RECEIVE_SIZE
char chatCountFunctionResponse[MAX_RECEIVE_SIZE]; // Matches MAX_RECEIVE_SIZE
char tempChatCountFunctionResponse[MAX_RECEIVE_SIZE]; // Matches MAX_RECEIVE_SIZE
char previousChatCountFunctionResponse[MAX_RECEIVE_SIZE]; // Matches MAX_RECEIVE_SIZE
char jsFunctionResponse[MAX_RECEIVE_SIZE];
char chatCountFunctionResponse[MAX_RECEIVE_SIZE];
char tempChatCountFunctionResponse[MAX_RECEIVE_SIZE];
char previousChatCountFunctionResponse[MAX_RECEIVE_SIZE];
char new_message_input_buffer[255];
int activeMessageCounter = 0;
int chatFriendlyNamesCounter = 0;
int coprocessorLoaded = 0;
int forceRedraw = 2; // this is how many 'iterations' of the UI that we need to see every element for
int forceRedrawChats= 2; // this is how many 'iterations' of the chat list UI that we need to see every element for, starting with 2 to draw the UI appropriately
int forceRedrawMessages = 2; // same as above but for messages
int ipAddressSet = 0;
int mouse_x;
int mouse_y;
@ -124,7 +122,7 @@ int sendNewChat = 0;
short box_input_len;
short box_len;
short new_message_input_buffer_len;
static short ip_input_buffer_len; // TODO: setting a length here will make the default `http://...` work, but doesn't work right -- maybe due to perf work in nuklear
static short ip_input_buffer_len;
struct nk_rect chats_window_size;
struct nk_rect graphql_input_window_size;
struct nk_rect message_input_window_size;
@ -175,8 +173,6 @@ void sendMessage() {
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: sendMessage");
#endif
writeSerialPortDebug(boutRefNum, "sendMessage!");
char output[2048];
sprintf(output, "%s&&&%.*s", activeChat, box_input_len, box_input_buffer);
@ -191,7 +187,7 @@ void sendMessage() {
getMessagesFromjsFunctionResponse();
forceRedraw = 3;
forceRedrawMessages = 3;
return;
}
@ -204,8 +200,6 @@ void getChats() {
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: getChats");
#endif
writeSerialPortDebug(boutRefNum, "getChats!");
callFunctionOnCoprocessor("getChats", "", jsFunctionResponse);
char *token = (char *)strtokm(jsFunctionResponse, ",");
@ -226,12 +220,9 @@ void sendIPAddressToCoprocessor() {
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: sendIPAddressToCoprocessor");
#endif
writeSerialPortDebug(boutRefNum, "sendIPAddressToCoprocessor!");
char output[2048];
sprintf(output, "%.*s", ip_input_buffer_len, ip_input_buffer);
writeSerialPortDebug(boutRefNum, output);
callFunctionOnCoprocessor("setIPAddress", output, jsFunctionResponse);
// now that the IP is set, we can get all of our chats
@ -249,17 +240,13 @@ void getMessages(char *thread, int page) {
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: getMessages");
#endif
writeSerialPortDebug(boutRefNum, "getMessages!");
char output[68];
sprintf(output, "%s&&&%d", thread, page);
// writeSerialPortDebug(boutRefNum, output);
callFunctionOnCoprocessor("getMessages", output, jsFunctionResponse);
// writeSerialPortDebug(boutRefNum, jsFunctionResponse);
getMessagesFromjsFunctionResponse();
forceRedraw = 3;
forceRedrawMessages = 3;
return;
}
@ -295,11 +282,13 @@ void getChatCounts() {
return;
}
//#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
#ifdef MESSAGES_FOR_MACINTOSH_DEBUGGING
// TODO: if you hear a random sysbeep, it's probably caused by a mismatch here
// potentially due to a bad serial port read or allocation. needs more investigation
writeSerialPortDebug(boutRefNum, "update current chat count");
writeSerialPortDebug(boutRefNum, chatCountFunctionResponse);
writeSerialPortDebug(boutRefNum, previousChatCountFunctionResponse);
//#endif
#endif
strcpy(previousChatCountFunctionResponse, chatCountFunctionResponse);
@ -428,7 +417,7 @@ void getChatCounts() {
}
}
forceRedraw = 3;
forceRedrawChats = 3;
return;
}
@ -439,14 +428,10 @@ void getHasNewMessagesInChat(char *thread) {
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: getHasNewMessagesInChat");
#endif
writeSerialPortDebug(boutRefNum, "getHasNewMessagesInChat!");
char output[68];
sprintf(output, "%s", thread);
// writeSerialPortDebug(boutRefNum, output);
callFunctionOnCoprocessor("hasNewMessagesInChat", output, jsFunctionResponse);
// writeSerialPortDebug(boutRefNum, jsFunctionResponse);
if (!strcmp(jsFunctionResponse, "true")) {
@ -469,16 +454,6 @@ Boolean checkCollision(struct nk_rect window) {
#ifdef DEBUG_FUNCTION_CALLS
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: checkCollision");
#endif
// writeSerialPortDebug(boutRefNum, "checkCollision!");
// Boolean testout = (window.x < mouse_x &&
// window.x + window.w > mouse_x &&
// window.y < mouse_y &&
// window.y + window.h > mouse_y);
// char str[255];
// sprintf(str, "what %d", testout);
// writeSerialPortDebug(boutRefNum, str);
// if truthy return, mouse is over window!
return (window.x < mouse_x &&
@ -534,7 +509,8 @@ static void nuklearApp(struct nk_context *ctx) {
if (nk_button_label(ctx, "save") || ip_edit_return_value == 17) {
ipAddressSet = 1;
forceRedraw = 2;
forceRedrawChats = 2;
forceRedrawMessages = 2;
sendIPAddressToCoprocessor();
}
}
@ -544,9 +520,14 @@ static void nuklearApp(struct nk_context *ctx) {
}
// eliminate the initially-set force-redraw
if (forceRedraw) {
if (forceRedrawChats) {
forceRedraw--;
forceRedrawChats--;
}
if (forceRedrawMessages) {
forceRedrawMessages--;
}
return;
@ -575,7 +556,8 @@ static void nuklearApp(struct nk_context *ctx) {
if (nk_button_label(ctx, "open chat")) {
sendNewChat = 0;
forceRedraw = 2;
forceRedrawChats = 2;
forceRedrawMessages = 2;
sprintf(activeChat, "%.*s", new_message_input_buffer_len, new_message_input_buffer);
@ -597,7 +579,14 @@ static void nuklearApp(struct nk_context *ctx) {
chatWindowCollision = checkCollision(chats_window_size);
if ((chatWindowCollision || forceRedraw) && nk_begin(ctx, "Chats", chats_window_size, NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
if ((chatWindowCollision || forceRedrawChats) && nk_begin(ctx, "Chats", chats_window_size, NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR)) {
// we force a redraw for several following iterations in case the mouse has moved away,
// we want to ensure that the button highlighting disappears
if (chatWindowCollision) {
forceRedrawChats = 3;
}
nk_layout_row_begin(ctx, NK_STATIC, 25, 1);
{
@ -681,7 +670,7 @@ static void nuklearApp(struct nk_context *ctx) {
nk_end(ctx);
}
if ((forceRedraw) && nk_begin_titled(ctx, "Message", activeChat, messages_window_size, NK_WINDOW_BORDER|NK_WINDOW_TITLE|NK_WINDOW_NO_SCROLLBAR)) {
if ((forceRedrawMessages) && nk_begin_titled(ctx, "Message", activeChat, messages_window_size, NK_WINDOW_BORDER|NK_WINDOW_TITLE|NK_WINDOW_NO_SCROLLBAR)) {
nk_layout_row_begin(ctx, NK_STATIC, 11, 1);
{
@ -700,9 +689,14 @@ static void nuklearApp(struct nk_context *ctx) {
nk_end(ctx);
}
if (forceRedraw) {
if (forceRedrawChats) {
forceRedraw--;
forceRedrawChats--;
}
if (forceRedrawMessages) {
forceRedrawMessages--;
}
}
@ -733,8 +727,8 @@ struct nk_context* initializeNuklearApp() {
#endif
sprintf(activeChat, "no active chat");
memset(&chatCountFunctionResponse, '\0', 32767);
memset(&previousChatCountFunctionResponse, '\0', 32767);
memset(&chatCountFunctionResponse, '\0', MAX_RECEIVE_SIZE);
memset(&previousChatCountFunctionResponse, '\0', MAX_RECEIVE_SIZE);
graphql_input_window_size = nk_rect(WINDOW_WIDTH / 2 - 118, 80, 234, 100);
chats_window_size = nk_rect(0, 0, 180, WINDOW_HEIGHT);
@ -744,7 +738,7 @@ struct nk_context* initializeNuklearApp() {
ctx = nk_quickdraw_init(WINDOW_WIDTH, WINDOW_HEIGHT);
refreshNuklearApp(false);
sprintf(ip_input_buffer, "http://"); // doesn't work due to bug, see variable definition
sprintf(ip_input_buffer, "http://");
ip_input_buffer_len = 7;
return ctx;

View File

@ -2,7 +2,7 @@
* Nuklear - 1.32.0 - public domain
* no warranty implied; use at your own risk.
* based on allegro5 version authored from 2015-2016 by Micha Mettke
* quickdraw version camhenlin 2021
* quickdraw version camhenlin 2021-2022
*
* v1 intent:
* - only default system font support
@ -258,7 +258,7 @@ NK_API void nk_quickdraw_del_image(struct nk_image* image) {
free(image);
}
// NOTE: you will need to generate this yourself!
// NOTE: you will need to generate this yourself if you want to add additional font support!
short widthFor12ptFont[128] = {
0,
10,
@ -1074,8 +1074,10 @@ void updateBounds(int top, int bottom, int left, int right) {
#endif
}
int lastCalls = 0;
int currentCalls;
#ifdef COMMAND_CACHING
int lastCalls = 0;
int currentCalls;
#endif
NK_API void nk_quickdraw_render(WindowPtr window, struct nk_context *ctx) {
@ -1083,7 +1085,9 @@ NK_API void nk_quickdraw_render(WindowPtr window, struct nk_context *ctx) {
writeSerialPortDebug(boutRefNum, "DEBUG_FUNCTION_CALLS: nk_quickdraw_render");
#endif
currentCalls = 1;
#ifdef COMMAND_CACHING
currentCalls = 1;
#endif
#ifdef PROFILING
PROFILE_START("IN nk_quickdraw_render");
@ -1136,16 +1140,15 @@ NK_API void nk_quickdraw_render(WindowPtr window, struct nk_context *ctx) {
#endif
#ifdef COMMAND_CACHING
writeSerialPortDebug(boutRefNum, "INCREMENT LAST CMD");
// TODO: if this becomes worth pursuing later, it causes address errors. I suspect that the memcpy
// command that builds up the last variable is not properly allocating memory.
// the address error pops up on the line of the conditional itself and can sometimes take hours to trigger.
if (currentCalls < lastCalls && lastCmd && lastCmd->next && lastCmd->next < ctx->memory.allocated) {
writeSerialPortDebug(boutRefNum, "INCREMENT LAST CMD: IN CONDITIONAL");
lastCmd = nk_ptr_add_const(struct nk_command, last, lastCmd->next);
}
currentCalls++;
writeSerialPortDebug(boutRefNum, "DONE INCREMENT LAST CMD");
#endif
}
@ -1155,8 +1158,6 @@ NK_API void nk_quickdraw_render(WindowPtr window, struct nk_context *ctx) {
memcpy(last, cmds, ctx->memory.allocated);
lastCalls = currentCalls;
#ifdef PROFILING
PROFILE_END("memcpy commands");
#endif
@ -1166,6 +1167,7 @@ NK_API void nk_quickdraw_render(WindowPtr window, struct nk_context *ctx) {
#endif
#ifdef COMMAND_CACHING
lastCalls = currentCalls;
lastInputWasBackspace = false;
#endif
@ -1465,93 +1467,13 @@ NK_API struct nk_context* nk_quickdraw_init(unsigned int width, unsigned int hei
last = calloc(1, MAX_MEMORY_IN_KB * 1024);
buf = calloc(1, MAX_MEMORY_IN_KB * 1024);
nk_init_fixed(&quickdraw.nuklear_context, buf, MAX_MEMORY_IN_KB * 1024, font);
// nk_init_default(&quickdraw.nuklear_context, font);
nk_style_push_font(&quickdraw.nuklear_context, font);
// this is pascal code but i think we would need to do something like this if we want this function
// to be responsible for setting the window size
// Region locUpdateRgn = NewRgn();
// SetRect(limitRect, kMinDocSize, kMinDocSize, kMaxDocSize, kMaxDocSize);
// // {call Window Manager to let user drag size box}
// growSize = GrowWindow(thisWindow, event.where, limitRect);
// SizeWindow(thisWindow, LoWord(growSize), HiWord(growSize), TRUE);
// SectRect(oldViewRect, myData^^.editRec^^.viewRect, oldViewRect);
// // {validate the intersection (don't update)}
// ValidRect(oldViewRect);
// // {invalidate any prior update region}
// InvalRgn(locUpdateRgn);
// DisposeRgn(locUpdateRgn);
nk_style_push_font(&quickdraw.nuklear_context, font);
quickdraw.nuklear_context.clip.copy = nk_quickdraw_clipboard_copy;
quickdraw.nuklear_context.clip.paste = nk_quickdraw_clipboard_paste;
quickdraw.nuklear_context.clip.userdata = nk_handle_ptr(0);
// // fix styles to be more "mac-like"
// struct nk_style *style;
// struct nk_style_toggle *toggle;
// struct nk_style_button *button;
// style = &quickdraw.nuklear_context.style;
// /* checkbox toggle */
// toggle = &style->checkbox;
// nk_zero_struct(*toggle);
// // toggle->normal = nk_style_item_color(nk_rgba(45, 45, 45, 255));
// // toggle->hover = nk_style_item_color(nk_rgba(80, 80, 80, 255)); // this is the "background" hover state regardless of checked status - we want light gray
// // toggle->active = nk_style_item_color(nk_rgba(255, 255, 255, 255)); // i can't tell what this does yet
// // toggle->cursor_normal = nk_style_item_color(nk_rgba(255, 255, 255, 255)); // this is the "checked" box itself - we want "black"
// // toggle->cursor_hover = nk_style_item_color(nk_rgba(255, 255, 255, 255)); // this is the hover state of a "checked" box - anything lighter than black is ok
// toggle->userdata = nk_handle_ptr(0);
// toggle->text_background = qd.black;
// // toggle->text_normal = nk_rgba(70, 70, 70, 255);
// // toggle->text_hover = nk_rgba(70, 70, 70, 255);
// // toggle->text_active = nk_rgba(70, 70, 70, 255);
// toggle->padding = nk_vec2(3, 3);
// toggle->touch_padding = nk_vec2(0,0);
// // toggle->border_color = nk_rgba(0,0,0,0);
// toggle->border = 0;
// toggle->spacing = 5;
// /* option toggle */
// toggle = &style->option;
// nk_zero_struct(*toggle);
// // toggle->normal = nk_style_item_color(nk_rgba(45, 45, 45, 255));
// // toggle->hover = nk_style_item_color(nk_rgba(80, 80, 80, 255)); // this is the "background" hover state regardless of checked status - we want light gray
// // toggle->active = nk_style_item_color(nk_rgba(255, 255, 255, 255)); // i can't tell what this does yet
// // toggle->cursor_normal = nk_style_item_color(nk_rgba(255, 255, 255, 255)); // this is the "checked" box itself - we want "black"
// // toggle->cursor_hover = nk_style_item_color(nk_rgba(255, 255, 255, 255)); // this is the hover state of a "checked" box - anything lighter than black is ok
// toggle->userdata = nk_handle_ptr(0);
// toggle->text_background = qd.black;
// // toggle->text_normal = nk_rgba(70, 70, 70, 255);
// // toggle->text_hover = nk_rgba(70, 70, 70, 255);
// // toggle->text_active = nk_rgba(70, 70, 70, 255);
// toggle->padding = nk_vec2(3, 3);
// toggle->touch_padding = nk_vec2(0,0);
// // toggle->border_color = nk_rgba(0,0,0,0);
// toggle->border = 0;
// toggle->spacing = 5;
// // button
// button = &style->button;
// nk_zero_struct(*button);
// // button->normal = nk_style_item_color(nk_rgba(0, 0, 0, 255));
// // button->hover = nk_style_item_color(nk_rgba(80, 80, 80, 255));
// // button->active = nk_style_item_color(nk_rgba(150, 150, 150, 255));
// // button->border_color = nk_rgba(255, 255, 255, 255);
// button->text_background = qd.black;
// // button->text_normal = nk_rgba(70, 70, 70, 255);
// // button->text_hover = nk_rgba(70, 70, 70, 255);
// // button->text_active = nk_rgba(0, 0, 0, 255);
// button->padding = nk_vec2(2,2);
// button->image_padding = nk_vec2(0,0);
// button->touch_padding = nk_vec2(0, 0);
// button->userdata = nk_handle_ptr(0);
// button->text_alignment = NK_TEXT_CENTERED;
// button->border = 1;
// button->rounding = 10;
// button->draw_begin = 0;
// button->draw_end = 0;
ForeColor(blackColor);
return &quickdraw.nuklear_context;