From 9b9d608134118e3b1ed63afb034af83fc7aab5be Mon Sep 17 00:00:00 2001 From: Severin Meyer Date: Thu, 18 Dec 2014 06:40:40 +0100 Subject: [PATCH] Reimplement the charmap to render the characters in-game, and reorganize the charmap to include new unicode characters from the xolonium font --- qcsrc/menu/skin-customizables.inc | 6 +- qcsrc/menu/xonotic/charmap.c | 311 ++++++++++++++++++++++++------ 2 files changed, 257 insertions(+), 60 deletions(-) diff --git a/qcsrc/menu/skin-customizables.inc b/qcsrc/menu/skin-customizables.inc index 1db6e6775d..ee0e76f399 100644 --- a/qcsrc/menu/skin-customizables.inc +++ b/qcsrc/menu/skin-customizables.inc @@ -212,8 +212,10 @@ SKINBEGIN SKINFLOAT(ALPHA_MODELTITLE, 1); // item: player name editor - SKINSTRING(GFX_CHARMAP, "charmap"); - SKINSTRING(GFX_CHARMAP_SELECTED, "charmapbutton"); + SKINVECTOR(COLOR_CHARMAP_CHAR, '1 1 1'); + SKINFLOAT(ALPHA_CHARMAP_CHAR, 1); + SKINVECTOR(COLOR_CHARMAP_FOCUS, '0 0 1'); + SKINFLOAT(ALPHA_CHARMAP_FOCUS, 0.5); // item: radio button SKINSTRING(GFX_RADIOBUTTON, "radiobutton"); diff --git a/qcsrc/menu/xonotic/charmap.c b/qcsrc/menu/xonotic/charmap.c index 6966aaf481..d65519c356 100644 --- a/qcsrc/menu/xonotic/charmap.c +++ b/qcsrc/menu/xonotic/charmap.c @@ -1,5 +1,5 @@ #ifdef INTERFACE -CLASS(XonoticCharmap) EXTENDS(Image) +CLASS(XonoticCharmap) EXTENDS(Item) METHOD(XonoticCharmap, configureXonoticCharmap, void(entity, entity)) METHOD(XonoticCharmap, mousePress, float(entity, vector)) METHOD(XonoticCharmap, mouseRelease, float(entity, vector)) @@ -7,146 +7,341 @@ CLASS(XonoticCharmap) EXTENDS(Image) METHOD(XonoticCharmap, mouseDrag, float(entity, vector)) METHOD(XonoticCharmap, keyDown, float(entity, float, float, float)) METHOD(XonoticCharmap, focusLeave, void(entity)) + METHOD(XonoticCharmap, resizeNotify, void(entity, vector, vector, vector, vector)) METHOD(XonoticCharmap, draw, void(entity)) - ATTRIB(XonoticCharmap, controlledTextbox, entity, NULL) - ATTRIB(XonoticCharmap, image, string, SKINGFX_CHARMAP) - ATTRIB(XonoticCharmap, image2, string, SKINGFX_CHARMAP_SELECTED) ATTRIB(XonoticCharmap, focusable, float, 1) - ATTRIB(XonoticCharmap, previouslySelectedCharacterCell, float, -1) - ATTRIB(XonoticCharmap, selectedCharacterCell, float, 0) - ATTRIB(XonoticCharmap, mouseSelectedCharacterCell, float, -1) + + METHOD(XonoticCharmap, moveFocus, void(entity, vector, vector)) + METHOD(XonoticCharmap, enterChar, void(entity)) + ATTRIB(XonoticCharmap, inputBox, entity, NULL) + ATTRIB(XonoticCharmap, realFontSize, vector, '0 0 0') + ATTRIB(XonoticCharmap, realCellSize, vector, '0 0 0') + ATTRIB(XonoticCharmap, focusedCell, vector, '-1 -1 0') + ATTRIB(XonoticCharmap, previouslyFocusedCell, vector, '-1 -1 0') ENDCLASS(XonoticCharmap) -entity makeXonoticCharmap(entity theTextbox); +entity makeXonoticCharmap(entity controlledInputBox); #endif #ifdef IMPLEMENTATION -entity makeXonoticCharmap(entity theTextbox) + +#define CHARMAP_COLS 14 +#define CHARMAP_ROWS 10 +string charmapRow0[CHARMAP_COLS]; +string charmapRow1[CHARMAP_COLS]; +string charmapRow2[CHARMAP_COLS]; +string charmapRow3[CHARMAP_COLS]; +string charmapRow4[CHARMAP_COLS]; +string charmapRow5[CHARMAP_COLS]; +string charmapRow6[CHARMAP_COLS]; +string charmapRow7[CHARMAP_COLS]; +string charmapRow8[CHARMAP_COLS]; +string charmapRow9[CHARMAP_COLS]; + +void charmap_initializeRows() +{ + if (charmapRow0[0] != "") + return; + + charmapRow0[0] = strzone(chr(0x2190)); + charmapRow0[1] = strzone(chr(0x2191)); + charmapRow0[2] = strzone(chr(0x2192)); + charmapRow0[3] = strzone(chr(0x2193)); + charmapRow0[4] = strzone(chr(0x25c0)); + charmapRow0[5] = strzone(chr(0x25b2)); + charmapRow0[6] = strzone(chr(0x25b6)); + charmapRow0[7] = strzone(chr(0x25bc)); + charmapRow0[8] = strzone(chr(0x25e3)); + charmapRow0[9] = strzone(chr(0x25e4)); + charmapRow0[10] = strzone(chr(0x25e5)); + charmapRow0[11] = strzone(chr(0x25e2)); + charmapRow0[12] = strzone(chr(0x2770)); + charmapRow0[13] = strzone(chr(0x2771)); + + charmapRow1[0] = strzone(chr(0x25A0)); + charmapRow1[1] = strzone(chr(0x25AC)); + charmapRow1[2] = strzone(chr(0x25AE)); + charmapRow1[3] = strzone(chr(0x25B0)); + charmapRow1[4] = strzone(chr(0x25C6)); + charmapRow1[5] = strzone(chr(0x25CF)); + charmapRow1[6] = strzone(chr(0x2605)); + charmapRow1[7] = strzone(chr(0x2764)); + charmapRow1[8] = strzone(chr(0x1F52B)); + charmapRow1[9] = strzone(chr(0x2316)); + charmapRow1[10] = strzone(chr(0x2747)); + charmapRow1[11] = strzone(chr(0x2748)); + charmapRow1[12] = strzone(chr(0x2772)); + charmapRow1[13] = strzone(chr(0x2773)); + + charmapRow2[0] = strzone(chr(0x1F47D)); + charmapRow2[1] = strzone(chr(0x2620)); + charmapRow2[2] = strzone(chr(0x2622)); + charmapRow2[3] = strzone(chr(0x2623)); + charmapRow2[4] = strzone(chr(0x2699)); + charmapRow2[5] = strzone(chr(0x269B)); + charmapRow2[6] = strzone(chr(0x26A0)); + charmapRow2[7] = strzone(chr(0x26A1)); + charmapRow2[8] = strzone(chr(0x274C)); + charmapRow2[9] = strzone(chr(0x1F680)); + charmapRow2[10] = strzone(chr(0x1F30C)); + charmapRow2[11] = strzone(chr(0x1F30D)); + charmapRow2[12] = strzone(chr(0x1F30E)); + charmapRow2[13] = strzone(chr(0x1F30F)); + + charmapRow3[0] = strzone(chr(0x1F601)); + charmapRow3[1] = strzone(chr(0x1F603)); + charmapRow3[2] = strzone(chr(0x1F604)); + charmapRow3[3] = strzone(chr(0x1F606)); + charmapRow3[4] = strzone(chr(0x1F607)); + charmapRow3[5] = strzone(chr(0x1F608)); + charmapRow3[6] = strzone(chr(0x1F609)); + charmapRow3[7] = strzone(chr(0x1F60A)); + charmapRow3[8] = strzone(chr(0x1F60E)); + charmapRow3[9] = strzone(chr(0x1F610)); + charmapRow3[10] = strzone(chr(0x1F612)); + charmapRow3[11] = strzone(chr(0x1F618)); + charmapRow3[12] = string_null; + charmapRow3[13] = string_null; + + charmapRow4[0] = strzone(chr(0x1F615)); + charmapRow4[1] = strzone(chr(0x1F61B)); + charmapRow4[2] = strzone(chr(0x1F61D)); + charmapRow4[3] = strzone(chr(0x1F61E)); + charmapRow4[4] = strzone(chr(0x1F61F)); + charmapRow4[5] = strzone(chr(0x1F620)); + charmapRow4[6] = strzone(chr(0x1F623)); + charmapRow4[7] = strzone(chr(0x1F62D)); + charmapRow4[8] = strzone(chr(0x1F62E)); + charmapRow4[9] = strzone(chr(0x1F632)); + charmapRow4[10] = strzone(chr(0x1F635)); + charmapRow4[11] = strzone(chr(0x1F634)); + charmapRow4[12] = string_null; + charmapRow4[13] = string_null; + + // Legacy characters: + + float i; + for(i = 0; i < 14; ++i) + charmapRow5[i] = strzone(chr(0xE0E1 + i)); + + for(i = 0; i < 12; ++i) + charmapRow6[i] = strzone(chr(0xE0EF + i)); + charmapRow6[12] = strzone(chr(0xE010)); + charmapRow6[13] = strzone(chr(0xE011)); + + for(i = 0; i < 10; ++i) + charmapRow7[i] = strzone(chr(0xE0B0 + i)); + charmapRow7[10] = strzone(chr(0xE0A1)); + charmapRow7[11] = strzone(chr(0xE0BF)); + charmapRow7[12] = strzone(chr(0xE0A6)); + charmapRow7[13] = strzone(chr(0xE0A5)); + + for(i = 0; i < 14; ++i) + charmapRow8[i] = strzone(chr(0xE0C1 + i)); + + for(i = 0; i < 12; ++i) + charmapRow9[i] = strzone(chr(0xE0CF + i)); + charmapRow9[12] = strzone(chr(0xE05B)); + charmapRow9[13] = strzone(chr(0xE05D)); +} + +string charmap_cellToChar(vector cell) +{ + if(!cvar("utf8_enable")) + return ""; + + if(cell_x >= CHARMAP_COLS) + return ""; + + switch(cell_y) + { + case 0: return charmapRow0[cell_x]; + case 1: return charmapRow1[cell_x]; + case 2: return charmapRow2[cell_x]; + case 3: return charmapRow3[cell_x]; + case 4: return charmapRow4[cell_x]; + case 5: return charmapRow5[cell_x]; + case 6: return charmapRow6[cell_x]; + case 7: return charmapRow7[cell_x]; + case 8: return charmapRow8[cell_x]; + case 9: return charmapRow9[cell_x]; + } + return ""; +} + +entity makeXonoticCharmap(entity controlledInputBox) { + charmap_initializeRows(); + entity me; me = spawnXonoticCharmap(); - me.configureXonoticCharmap(me, theTextbox); + me.configureXonoticCharmap(me, controlledInputBox); return me; } -string CharMap_CellToChar(float c) +void XonoticCharmap_configureXonoticCharmap(entity me, entity controlledInputBox) { - if (cvar("utf8_enable")) { - if(c == 13) - return chr(0xE000 + 127); - else if(c < 32) - return chr(0xE000 + c); - else - return chr(0xE000 + c + 96); - } else { - if(c == 13) - return chr(127); - else if(c < 32) - return chr(c); - else - return chr(c + 96); - } + me.inputBox = controlledInputBox; + me.realCellSize = eX / CHARMAP_COLS + eY / CHARMAP_ROWS; } -void XonoticCharmap_configureXonoticCharmap(entity me, entity theTextbox) +void XonoticCharmap_resizeNotify(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize) { - me.controlledTextbox = theTextbox; - me.configureImage(me, me.image); + SUPER(XonoticCharmap).resizeNotify(me, relOrigin, relSize, absOrigin, absSize); + + if((me.realCellSize_x * absSize_x) > (me.realCellSize_y * absSize_y)) + { + me.realFontSize_x = me.realCellSize_y * absSize_y / absSize_x; + me.realFontSize_y = me.realCellSize_y; + } + else + { + me.realFontSize_x = me.realCellSize_x; + me.realFontSize_y = me.realCellSize_x * absSize_x / absSize_y; + } } float XonoticCharmap_mouseMove(entity me, vector coords) { - float x, y, c; - x = floor(coords_x * 16); - y = floor(coords_y * 10); - if(x < 0 || y < 0 || x >= 16 || y >= 10) + me.focusedCell_x = floor(coords_x * CHARMAP_COLS); + me.focusedCell_y = floor(coords_y * CHARMAP_ROWS); + + if(me.focusedCell_x < 0 || me.focusedCell_y < 0 || + me.focusedCell_x >= CHARMAP_COLS || me.focusedCell_y >= CHARMAP_ROWS) { - me.mouseSelectedCharacterCell = -1; + me.focusedCell = '-1 -1 0'; return 0; } - c = y * 16 + x; - if(c != me.mouseSelectedCharacterCell || me.mouseSelectedCharacterCell != me.selectedCharacterCell) - me.mouseSelectedCharacterCell = me.selectedCharacterCell = c; + return 1; } + float XonoticCharmap_mouseDrag(entity me, vector coords) { return me.mouseMove(me, coords); } + float XonoticCharmap_mousePress(entity me, vector coords) { me.mouseMove(me, coords); - if(me.mouseSelectedCharacterCell >= 0) + + if(me.focusedCell_x >= 0) { me.pressed = 1; - me.previouslySelectedCharacterCell = me.selectedCharacterCell; + me.previouslyFocusedCell = me.focusedCell; } + return 1; } + float XonoticCharmap_mouseRelease(entity me, vector coords) { if(!me.pressed) return 0; + me.mouseMove(me, coords); - if(me.selectedCharacterCell == me.previouslySelectedCharacterCell) - me.controlledTextbox.enterText(me.controlledTextbox, CharMap_CellToChar(me.selectedCharacterCell)); + + if(me.focusedCell == me.previouslyFocusedCell) + me.enterChar(me); + me.pressed = 0; return 1; } + float XonoticCharmap_keyDown(entity me, float key, float ascii, float shift) { switch(key) { case K_LEFTARROW: case K_KP_LEFTARROW: - me.selectedCharacterCell = mod(me.selectedCharacterCell + 159, 160); + me.moveFocus(me, me.focusedCell, '-1 0 0'); return 1; case K_RIGHTARROW: case K_KP_RIGHTARROW: - me.selectedCharacterCell = mod(me.selectedCharacterCell + 1, 160); + me.moveFocus(me, me.focusedCell, '1 0 0'); return 1; case K_UPARROW: case K_KP_UPARROW: - me.selectedCharacterCell = mod(me.selectedCharacterCell + 144, 160); + me.moveFocus(me, me.focusedCell, '0 -1 0'); return 1; case K_DOWNARROW: case K_KP_DOWNARROW: - me.selectedCharacterCell = mod(me.selectedCharacterCell + 16, 160); + me.moveFocus(me, me.focusedCell, '0 1 0'); return 1; case K_HOME: case K_KP_HOME: - me.selectedCharacterCell = 0; + me.focusedCell = '0 0 0'; return 1; case K_END: case K_KP_END: - me.selectedCharacterCell = 159; + me.focusedCell_x = CHARMAP_COLS - 1; + me.focusedCell_y = CHARMAP_ROWS - 1; return 1; - case K_SPACE: case K_ENTER: case K_KP_ENTER: case K_INS: case K_KP_INS: - me.controlledTextbox.enterText(me.controlledTextbox, CharMap_CellToChar(me.selectedCharacterCell)); + me.enterChar(me); return 1; default: - return me.controlledTextbox.keyDown(me.controlledTextbox, key, ascii, shift); + return me.inputBox.keyDown(me.inputBox, key, ascii, shift); } } + +void XonoticCharmap_moveFocus(entity me, vector initialCell, vector step) +{ + me.focusedCell_x = mod(me.focusedCell_x + step_x + CHARMAP_COLS, CHARMAP_COLS); + me.focusedCell_y = mod(me.focusedCell_y + step_y + CHARMAP_ROWS, CHARMAP_ROWS); + + if(me.focusedCell != initialCell) // Recursion break + if(charmap_cellToChar(me.focusedCell) == "") + me.moveFocus(me, initialCell, step); +} + +void XonoticCharmap_enterChar(entity me) +{ + string character = charmap_cellToChar(me.focusedCell); + if(character != "") + me.inputBox.enterText(me.inputBox, character); +} + void XonoticCharmap_focusLeave(entity me) { - me.controlledTextbox.saveCvars(me.controlledTextbox); + me.inputBox.saveCvars(me.inputBox); } + void XonoticCharmap_draw(entity me) { - if(me.focused) + string character; + vector cell, cellPos, charPos; + cell = '0 0 0'; + cellPos = '0 0 0'; + charPos = '0 0 0'; + + for(cell_y = 0; cell_y < CHARMAP_ROWS; ++cell_y) { - if(!me.pressed || (me.selectedCharacterCell == me.previouslySelectedCharacterCell)) + charPos_y = cell_y / CHARMAP_ROWS + (me.realCellSize_y - me.realFontSize_y) / 2; + for(cell_x = 0; cell_x < CHARMAP_COLS; ++cell_x) { - vector c; - c = eX * (mod(me.selectedCharacterCell, 16) / 16.0); - c += eY * (floor(me.selectedCharacterCell / 16.0) / 10.0); - draw_Picture(c, me.image2, '0.0625 0.1 0', '1 1 1', 1); + character = charmap_cellToChar(cell); + + if(character == "") + continue; + + // Draw focused cell + if(cell == me.focusedCell && me.focused) + { + if(!me.pressed || me.focusedCell == me.previouslyFocusedCell) + { + cellPos_x = mod(me.focusedCell_x, CHARMAP_COLS) / CHARMAP_COLS; + cellPos_y = mod(me.focusedCell_y, CHARMAP_ROWS) / CHARMAP_ROWS; + draw_Fill(cellPos, me.realCellSize, SKINCOLOR_CHARMAP_FOCUS, SKINALPHA_CHARMAP_FOCUS); + } + } + + // Draw character + charPos_x = cell_x / CHARMAP_COLS + me.realCellSize_x / 2; + draw_CenterText(charPos, character, me.realFontSize, SKINCOLOR_CHARMAP_CHAR, SKINALPHA_CHARMAP_CHAR, 0); } } - SUPER(XonoticCharmap).draw(me); } #endif -- 2.39.2