#include "emgui.h" #include "emgui_internal.h" #include "memory/LinearAllocator.h" #include "GFXBackend.h" #include "MicroKnightFont.h" #include "External/stb_truetype.h" #include "External/stb_image.h" #include #include #include #if defined(emguiGUI_MACOSX) #include #else #define PATH_MAX 1024 #endif struct EmguiImage; typedef struct MouseState { int x; int y; int down; } MouseState; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef struct EmguiState { MouseState mouse; int hotItem; int activeItem; int kbdItem; int keyCode; int keyMod; int lastWidget; } EmguiState; struct EmguiImageCache { uint64_t hash; uint64_t handle; int32_t width; int32_t height; }; enum { MAX_IMAGES = 1024, EM_FONTBITMAP_WIDTH = 512, EM_FONTBITMAP_HEIGHT = 512, }; static LinearAllocator s_allocator; static LinearAllocatorRewindPoint s_rewindPoint; static int g_loadedFontsCount = 1; LoadedFont g_loadedFonts[MAX_FONTS]; EmguiState g_emguiGuiState; uint32_t g_controlId; uint32_t g_currentFont = 1; uint32_t g_temp; uint32_t g_defaultFont; static int s_activeLayer = 0; struct RenderData s_renderData; static struct EmguiImageCache s_imageCache[MAX_IMAGES]; static int s_imageCacheCount; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// enum GuiPlacementState { PLACEMENTSTATE_NONE, PLACEMENTSTATE_HORIZONAL, PLACEMENTSTATE_VERTICAL, }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// typedef struct GuiPlacementInfo { enum GuiPlacementState state; int x; int y; } GuiPlacementInfo; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static GuiPlacementInfo g_placementInfo; EmguiControlInfo g_controls[MAX_CONTROLS]; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static EMGUI_INLINE EmguiControlInfo* newControl() { EmguiControlInfo* control = &g_controls[g_controlId]; g_controlId++; return control; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_beginHorizontalStackPanelXY(int x, int y) { g_placementInfo.state = PLACEMENTSTATE_HORIZONAL; g_placementInfo.x = x; g_placementInfo.y = y; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_beginVerticalStackPanelXY(int x, int y) { g_placementInfo.state = PLACEMENTSTATE_VERTICAL; g_placementInfo.x = x; g_placementInfo.y = y; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // taken from: // http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/142054 // // djb :: 99.8601 percent coverage (60 collisions out of 42884) // elf :: 99.5430 percent coverage (196 collisions out of 42884) // sdbm :: 100.0000 percent coverage (0 collisions out of 42884) (this is the algo used) // ... static uint32_t quickHash(const char* string) { uint32_t c; uint32_t hash = 0; const uint8_t* str = (const uint8_t*)string; while ((c = *str++)) hash = c + (hash << 6) + (hash << 16) - hash; return hash & 0x7FFFFFFF; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// uint64_t loadImage(int* width, int* height, void* image, int length, enum EmguiMemoryLocation location) { int w = 0, h = 0, c = 0; void* imageData = 0; int i, imageCount = s_imageCacheCount; uint64_t imageId = (uint64_t)~0; uint64_t hash = (uintptr_t)image; if (location == EMGUI_LOCATION_FILE) hash = quickHash((const char*)image); // See if we have the image loaded already for (i = 0; i < imageCount; ++i) { if (s_imageCache[i].hash == hash) { *width = s_imageCache[i].width; *height = s_imageCache[i].height; return s_imageCache[i].handle; } } if (location == EMGUI_LOCATION_FILE) { imageData = stbi_load(image, &w, &h, &c, 0); if (!imageData) printf("EMGUI: Unable to load image %s\n", (char*)image); } else if (location == EMGUI_LOCATION_MEMORY) { imageData = stbi_load_from_memory(image, length, &w, &h, &c, 0); if (!imageData) printf("EMGUI: Unable to load image (from memory %p)\n", image); } if (imageData) imageId = EMGFXBackend_createTexture(imageData, w, h, c); s_imageCacheCount++; s_imageCache[imageCount].hash = hash; s_imageCache[imageCount].handle = imageId; s_imageCache[imageCount].width = w; s_imageCache[imageCount].height = h; *width = s_imageCache[i].width; *height = s_imageCache[i].height; return imageId; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void createDefaultFont() { struct LoadedFont* loadedFont = &g_loadedFonts[0]; uint8_t* tempColorData; uint8_t* colorData = tempColorData = (uint8_t*)malloc(128 * 128); const uint8_t* data = s_microkinghtFontData; uint32_t i; // Build new texture for (i = 0; i < (128 * 128) / 8; ++i) { uint8_t color = *data++; // font data is packed as 1 bit per pixel *tempColorData++ = ((color >> 7) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 6) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 5) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 4) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 3) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 2) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 1) & 1) ? 0xff : 0; *tempColorData++ = ((color >> 0) & 1) ? 0xff : 0; } loadedFont->handle = EMGFXBackend_createFontTexture(colorData, 128, 128); strcpy(loadedFont->name, "Microknight"); loadedFont->altLookup = (unsigned short*)&s_microknightLayout[0].x; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// int Emgui_loadFontBitmap(const char* buffer, int size, enum EmguiMemoryLocation location, int rangeStart, int rangeEnd, EmguiFontLayout* layout) { struct LoadedFont* loadedFont; void* imageData = 0; int fontId = 0, width = 0, height = 0, comp = 0; // Load the texture in to memory if (location == EMGUI_LOCATION_FILE) imageData = stbi_load(buffer, &width, &height, &comp, 0); else if (location == EMGUI_LOCATION_MEMORY) imageData = stbi_load_from_memory((void*)buffer, size, &width, &height, &comp, 0); // make sure we got the image data and that its an 8-bit (alpha only) texture if (!imageData || comp != 1) { free(imageData); return -1; } fontId = g_loadedFontsCount++; loadedFont = &g_loadedFonts[fontId]; memset(loadedFont, 0, sizeof(LoadedFont)); loadedFont->width = (uint16_t)width; loadedFont->height = (uint16_t)height; loadedFont->rangeStart = rangeStart; loadedFont->rangeEnd = rangeEnd; loadedFont->handle = EMGFXBackend_createFontTexture(imageData, width, height); loadedFont->layout = layout; free(imageData); return fontId; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Track both y and x size and return a mask of them uint32_t Emgui_getTextSize(const char* text) { uint32_t x_size = 0; int y_size = 0; int range_start; int range_end; int c; const LoadedFont* font = &g_loadedFonts[g_currentFont]; if (!font->layout) return (8 << 16) | strlen(text) * 8; range_start = font->rangeStart; range_end = font->rangeEnd; c = (unsigned char)*text++; while (c != 0) { if (c >= range_start && c < range_end) { const int offset = c - range_start; x_size += font->layout[offset].xadvance; if (font->layout[offset].height > y_size) y_size = font->layout[offset].height; } c = *text++; } return (y_size << 16) | x_size; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Emgui_create() { const uint32_t size = 1024 * 1024; LinearAllocator_create(&s_allocator, malloc(size), size); createDefaultFont(); g_emguiGuiState.kbdItem = -1; return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_begin() { g_controlId = 1; g_controls[0].type = EMGUI_DRAWTYPE_NONE; memset(&s_renderData, 0, sizeof(s_renderData)); memset(&g_placementInfo, 0, sizeof(GuiPlacementInfo)); s_rewindPoint = LinearAllocator_getRewindPoint(&s_allocator); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static bool Emgui_regionHit(const EmguiControlInfo* control) { const int mouse_x = g_emguiGuiState.mouse.x; const int mouse_y = g_emguiGuiState.mouse.y; // need to figure out why adding 4 makes this better const int control_x = control->x + 4; const int control_y = control->y + 4; /* printf("%d %d - %d %d %d %d\n", mouse_x, mouse_y, control_x, control_y, control_x + control->width, control_y + control->height); */ if (mouse_x < control_x || mouse_y < control_y || mouse_x >= control_x + control->width || mouse_y >= control_y + control->height) { return false; } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_reset() { g_emguiGuiState.mouse.x = -1; g_emguiGuiState.mouse.y = -1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static bool Emgui_regionHitSlider(const EmguiControlInfo* control) { const int mouse_x = g_emguiGuiState.mouse.x; const int mouse_y = g_emguiGuiState.mouse.y; const int slider_thumb_x = control->sliderThumbX + 4; const int slider_thumb_y = control->sliderThumbY + 4; if (mouse_x < slider_thumb_x || mouse_y < slider_thumb_y || mouse_x >= slider_thumb_x + control->sliderThumbWidth || mouse_y >= slider_thumb_y + control->sliderThumbHeight) { return false; } return true; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_fill(uint32_t color, int x, int y, int w, int h) { Emgui_fillGrad(color, color, x, y, w, h); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_fillGrad(uint32_t color0, uint32_t color1, int x, int y, int w, int h) { const int active_layer = s_activeLayer; struct DrawFillCommand* command = LinearAllocator_allocZero(&s_allocator, struct DrawFillCommand); command->x = x; command->y = y; command->width = w; command->height = h; command->color0 = color0; command->color1 = color1; if (!s_renderData.layers[active_layer].fillCommands) { s_renderData.layers[active_layer].fillCommands = command; // first command s_renderData.layers[active_layer].fillCommandsTail = command; } else { s_renderData.layers[active_layer].fillCommandsTail->next = command; s_renderData.layers[active_layer].fillCommandsTail = command; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_drawBorder(uint32_t color0, uint32_t color1, int x, int y, int w, int h) { const uint32_t size = 2; Emgui_fill(color0, x, y, size, h); Emgui_fill(color0, x, y, w, size); Emgui_fill(color1, x + w, y, size, h + size); Emgui_fill(color1, x, y + h, w, size); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_textLabelXY(const char* text, int x, int y) { Emgui_drawText(text, x, y, 0xffffffff); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// float floatClamp(float value, float low, float high) { if (value < low) value = low; if (value > high) value = high; return value; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Emgui_slider(int x, int y, int w, int h, int start, int end, int largeVal, enum EmguiSliderDirection dir, int itemSpace, int* ivalue) { //int thumbPosition = 0; int controlId = 0; float value = (float)*ivalue; float range; int left, height; int thumb_width = 0, thumb_height = 0; EmguiControlInfo* control = 0; // Setup the control controlId = (int)g_controlId++; control = &g_controls[controlId]; control->type = EMGUI_DRAWTYPE_SLIDER; control->x = x; control->y = y; control->width = w; control->height = h; // considering how much stuff we have have in the slider we need to calculate how much space the scolling area actually // is so we can resize the thumb range = (float)(end - start); if (dir == EMGUI_SLIDERDIR_HORIZONTAL) { float lw = (float)largeVal; float fw = (float)w; thumb_width = (int)((lw * fw) / (range + 1.0f)); left = x + (int)((w - thumb_width) * (value / (float)end)); if (thumb_width < 0) thumb_width = 2; control->sliderThumbX = left; control->sliderThumbY = y + 1; control->sliderThumbWidth = thumb_width; control->sliderThumbHeight = h; } else { float lw = (float)largeVal; float fh = (float)h; thumb_height = (int) ((lw * fh) / (range + 1.0f)); height = y + (int)((h - thumb_height) * (value / (float)end)); if (thumb_height < 0) thumb_height = 2; control->sliderThumbX = x + 1; control->sliderThumbY = height; control->sliderThumbWidth = w; control->sliderThumbHeight = thumb_height; } Emgui_fill(Emgui_color32(255, 255, 255, 255), control->sliderThumbX, control->sliderThumbY, control->sliderThumbWidth, control->sliderThumbHeight); if (Emgui_regionHitSlider(control)) { g_emguiGuiState.hotItem = controlId; if (g_emguiGuiState.activeItem == 0 && g_emguiGuiState.mouse.down) g_emguiGuiState.activeItem = controlId; } if (g_emguiGuiState.activeItem == controlId) { if (dir == EMGUI_SLIDERDIR_HORIZONTAL) { int mouseRelative = g_emguiGuiState.mouse.x - (x + thumb_width / 2); mouseRelative = eclampi(mouseRelative, 0, w - thumb_width - 1); value = ((float)mouseRelative / (float)(w - thumb_width)) * (float)end; *ivalue = (int)value; printf("%f %d (clamp %d) %f\n", (float)mouseRelative / (float)(w), mouseRelative, (w - thumb_width - 1), value); } else { int mouseRelative = g_emguiGuiState.mouse.y - (y + thumb_height / 2); mouseRelative = eclampi(mouseRelative, 0, h - thumb_height - 1); value = ((float)mouseRelative / (float)(h - thumb_height)) * (float)end; *ivalue = (int)value; } return true; } return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_textLabel(const char* text) { uint32_t controlId = 0; EmguiControlInfo* control = 0; // Setup the control controlId = g_controlId++; control = &g_controls[controlId]; control->type = EMGUI_DRAWTYPE_TEXT; control->x = g_placementInfo.x; control->y = g_placementInfo.y; control->width = 0; //getTextSize(text); control->height = 9; // fixme control->text = LinearAllocator_allocString(&s_allocator, text); control->color = 0; control->fontId = g_currentFont; switch (g_placementInfo.state) { case PLACEMENTSTATE_NONE : { break; } case PLACEMENTSTATE_HORIZONAL : { g_placementInfo.x += control->width; break; } case PLACEMENTSTATE_VERTICAL : { g_placementInfo.y += 9; // TODO: Use correct size from font break; } } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void drawImage(uint64_t imageId, uint32_t color, int x, int y, int w, int h) { const int active_layer = s_activeLayer; struct DrawImageCommand* command = LinearAllocator_alloc(&s_allocator, struct DrawImageCommand); command->next = 0; command->imageId = imageId; command->x = x; command->y = y; command->width = w; command->height = h; command->color = color; if (!s_renderData.layers[active_layer].imageCommands) { s_renderData.layers[active_layer].imageCommands = command; s_renderData.layers[active_layer].imageCommandsTail = command; } else { s_renderData.layers[active_layer].imageCommandsTail->next = command; s_renderData.layers[active_layer].imageCommandsTail = command; } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void drawText(const char* text, bool flipped, int x, int y, uint32_t color) { struct DrawTextCommand* temp; struct DrawTextCommand* command = LinearAllocator_alloc(&s_allocator, struct DrawTextCommand); command->x = x; command->y = y; command->text = LinearAllocator_allocString(&s_allocator, text); command->color = color; command->flipped = flipped; assert(g_currentFont < EMGUI_MAX_FONTS); temp = s_renderData.layers[s_activeLayer].textCommands[g_currentFont]; s_renderData.layers[s_activeLayer].textCommands[g_currentFont] = command; command->next = temp; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_drawTextFlipped(const char* text, int x, int y, uint32_t color) { drawText(text, true, x, y, color); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_drawText(const char* text, int x, int y, uint32_t color) { drawText(text, false, x, y, color); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static void* readFileToMemory(const char* filename) { int size; void* fileBuffer; FILE* file; file = fopen(filename, "rb"); if (!file) return false; fseek(file, 0, SEEK_END); size = ftell(file); fseek(file, 0, SEEK_SET); if (!(fileBuffer = malloc(size))) { fclose(file); return false; } fread(fileBuffer, 1, size, file); fclose(file); return fileBuffer; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// uint32_t Emgui_loadFont(const char* ttfFontname, float fontHeight) { uint32_t fontId = 0; struct LoadedFont* loadedFont; uint8_t* fontBitmap = 0; void* ttfFontBuffer = readFileToMemory(ttfFontname); if (!ttfFontBuffer) return false; if (g_loadedFontsCount > MAX_FONTS) return false; if (!(fontBitmap = malloc(EM_FONTBITMAP_WIDTH * EM_FONTBITMAP_HEIGHT))) return false; fontId = g_loadedFontsCount++; loadedFont = &g_loadedFonts[fontId]; memset(loadedFont, 0, sizeof(LoadedFont)); strncpy(loadedFont->name, ttfFontname, 512); // TODO: Support support different texturesizes and utf8/non-ascii chars? stbtt_BakeFontBitmap(ttfFontBuffer, 0, fontHeight, fontBitmap, EM_FONTBITMAP_WIDTH, EM_FONTBITMAP_HEIGHT, 32, 96, loadedFont->cData); loadedFont->handle = EMGFXBackend_createFontTexture(fontBitmap, EM_FONTBITMAP_WIDTH, EM_FONTBITMAP_HEIGHT); free(ttfFontBuffer); free(fontBitmap); return fontId; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setFont(uint32_t fontId) { g_currentFont = fontId; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setDefaultFont() { Emgui_setFont(0); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static uint32_t genericImageControl(const char* filename) { uint32_t controlId = 0; EmguiControlInfo* control = 0; struct EmguiImage* image = 0; //loadImage(filename); if (!image) return (uint32_t)~0; // Setup the control controlId = g_controlId++; control = &g_controls[controlId]; control->type = EMGUI_DRAWTYPE_IMAGE; control->x = g_placementInfo.x; control->y = g_placementInfo.y; //control->width = image->width; //control->height = image->height; //control->imageData = image; //updatePlacement(); switch (g_placementInfo.state) { case PLACEMENTSTATE_NONE : { break; } case PLACEMENTSTATE_HORIZONAL : { //g_placementInfo.x += image->width; break; } case PLACEMENTSTATE_VERTICAL : { //g_placementInfo.y += image->height; break; } } return controlId; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_staticImage(const char* filename) { genericImageControl(filename); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* static void highlightControl(EmguiControlInfo* control) { Emgui_fill(0xb0ffffff, control->x, control->y, control->width, control->height); } */ /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Emgui_buttonImage(const char* filename) { EmguiControlInfo* control; int controlId = 0; controlId = genericImageControl(filename); if (controlId == ~0) return false; control = &g_controls[controlId]; if (Emgui_regionHit(control)) { g_emguiGuiState.hotItem = controlId; if (g_emguiGuiState.activeItem == 0 && g_emguiGuiState.mouse.down) g_emguiGuiState.activeItem = controlId; //highlightControl(control); } if (g_emguiGuiState.mouse.down == 0 && g_emguiGuiState.hotItem == controlId && g_emguiGuiState.activeItem == controlId) return true; return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Emgui_buttonCoords(const char* text, uint32_t color, int x, int y, int width, int height) { EmguiControlInfo* control; int controlId = 0; uint32_t textSize = Emgui_getTextSize(text); uint32_t size_x = textSize & 0xffff; uint32_t size_y = textSize >> 16; Emgui_drawBorder(color, color, x, y, width, height); Emgui_textLabelXY(text, x + (width - size_x) / 2, y + (height - size_y) / 2); controlId = (int)g_controlId++; control = &g_controls[controlId]; control->x = x; control->y = y; control->width = width; control->height = height; control->color = color; if (Emgui_regionHit(control)) { g_emguiGuiState.hotItem = controlId; if (g_emguiGuiState.activeItem == 0 && g_emguiGuiState.mouse.down) g_emguiGuiState.activeItem = controlId; } if (g_emguiGuiState.mouse.down == 0 && g_emguiGuiState.hotItem == controlId && g_emguiGuiState.activeItem == controlId) { return true; } return false; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_radioButtonImage(void* image0, int size0, void* image1, int size1, enum EmguiMemoryLocation location, uint32_t color, int x, int y, bool* stateIn) { EmguiControlInfo* control; bool state = *stateIn; int controlId = 0; int w0 = -1, h0 = -1; int w1 = -1, h1 = -1; int w, h; uint64_t i0 = loadImage(&w0, &h0, image0, size0, location); uint64_t i1 = loadImage(&w1, &h1, image1, size1, location); if ((uint64_t)~0 == i0 || (uint64_t)~0 == i1) { printf("EMGUI: (radioButton) Unable to create due to fail of loading image(s)\n"); return; } controlId = (int)g_controlId++; control = &g_controls[controlId]; w = state ? w0 : w1; h = state ? h0 : h1; control->x = x; control->y = y; control->width = w; control->height = h; control->color = color; if (Emgui_regionHit(control)) { g_emguiGuiState.hotItem = controlId; if (g_emguiGuiState.activeItem == 0 && g_emguiGuiState.mouse.down) g_emguiGuiState.activeItem = controlId; } if (g_emguiGuiState.mouse.down == 0 && g_emguiGuiState.hotItem == controlId && g_emguiGuiState.activeItem == controlId) { state = !state; } if (state) drawImage(i0, color, x, y, w0, h0); else drawImage(i1, color, x, y, w1, h1); *stateIn = state; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_end() { if (g_emguiGuiState.mouse.down == 0) { g_emguiGuiState.activeItem = 0; } else { if (g_emguiGuiState.activeItem == 0) g_emguiGuiState.activeItem = -1; } g_emguiGuiState.keyCode = 0; EMGFXBackend_render(); // Rewind the linear allocator LinearAllocator_rewind(&s_allocator, s_rewindPoint); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_editBoxXY(int x, int y, int width, int height, int bufferLength, char* buffer) { EmguiControlInfo* control; int controlId = 0; const int keyCode = g_emguiGuiState.keyCode; uint32_t color = Emgui_color32(200, 200, 127, 255); controlId = (int)g_controlId++; control = &g_controls[controlId]; control->x = x; control->y = y; control->width = width; control->height = height; control->color = color; if (Emgui_regionHit(control)) { g_emguiGuiState.hotItem = controlId; if (g_emguiGuiState.activeItem == 0 && g_emguiGuiState.mouse.down) { g_emguiGuiState.activeItem = controlId; g_emguiGuiState.kbdItem = controlId; } } // if we have keyboard active on this control we need to modify the text if (g_emguiGuiState.kbdItem == controlId && keyCode != 0) { int len = strlen(buffer); switch (keyCode) { case EMGUI_KEY_TAB : { if (g_emguiGuiState.keyMod & EMGUI_KEY_SHIFT) { if (controlId - 1 <= 0) { g_emguiGuiState.kbdItem = -1; g_emguiGuiState.keyCode = 0; } else { g_emguiGuiState.kbdItem = controlId - 1; g_emguiGuiState.keyCode = 0; } break; } else { if (controlId + 1 >= 4) { g_emguiGuiState.kbdItem = -1; g_emguiGuiState.keyCode = 0; } else { g_emguiGuiState.kbdItem = controlId + 1; g_emguiGuiState.keyCode = 0; } } break; } case EMGUI_KEY_ENTER : { g_emguiGuiState.kbdItem = -1; g_emguiGuiState.keyCode = 0; break; } case EMGUI_KEY_BACKSPACE : { buffer[emaxi(len - 1, 0)] = 0; break; } default : { // Rocket hack: // Currenty for rocket we only need 0-9 as input (for the edit field // so we only update here if those are the keys int offset = emini(bufferLength - 2, len); if (keyCode >= '0' && keyCode <= '9') { buffer[offset + 0] = (char)keyCode; buffer[offset + 1] = 0; } break; } } } Emgui_fillGrad(Emgui_color32(70, 70, 70, 255), Emgui_color32(30, 30, 30, 255), x, y, width, height); Emgui_drawText(buffer, x + 2, y, color); if (g_emguiGuiState.kbdItem == controlId) { int text_size = Emgui_getTextSize(buffer) & 0xffff; uint32_t color0 = Emgui_color32(200, 200, 127, 127); uint32_t color1 = Emgui_color32(200, 200, 127, 127); Emgui_drawBorder(color0, color1, x, y, width, height); Emgui_fill(Emgui_color32(200, 200, 127, 200), x + text_size + 2, y + 2, 2, height - 2); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_sendKeyinput(int keyCode, int modifier) { g_emguiGuiState.keyCode = keyCode; g_emguiGuiState.keyMod = modifier; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setMousePos(int posX, int posY) { g_emguiGuiState.mouse.x = posX; g_emguiGuiState.mouse.y = posY; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setMouseLmb(int state) { g_emguiGuiState.mouse.down = state; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// bool Emgui_hasKeyboardFocus() { return g_emguiGuiState.kbdItem != -1; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setFirstControlFocus() { g_emguiGuiState.kbdItem = 1; g_emguiGuiState.keyCode = 0; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setLayer(int layer) { s_activeLayer = layer; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void Emgui_setScissor(int x, int y, int w, int h) { const int active_layer = s_activeLayer; s_renderData.layers[active_layer].scissor.x = x; s_renderData.layers[active_layer].scissor.y = y; s_renderData.layers[active_layer].scissor.width = w; s_renderData.layers[active_layer].scissor.height = h; }