1 module unde.keybar.lib; 2 3 import berkeleydb.all; 4 5 import derelict.sdl2.sdl; 6 import derelict.sdl2.ttf; 7 import derelict.sdl2.image; 8 9 import unde.global_state; 10 import unde.font; 11 import unde.viewers.image_viewer.lib; 12 import unde.command_line.lib; 13 import unde.slash; 14 15 import std.stdio; 16 import std..string; 17 import std.math; 18 import std.range.primitives; 19 import std.file; 20 import std.algorithm.sorting; 21 import std.process; 22 import core.stdc.locale; 23 import core.sys.windows.windows; 24 25 struct KeyHandler 26 { 27 void delegate (GlobalState gs) handler; 28 string description; 29 string icon; 30 } 31 32 struct ButtonParms 33 { 34 SDL_Rect rect; 35 SDL_Color color; 36 } 37 38 struct Layout 39 { 40 string short_name; 41 string name; 42 43 string[][3] letters; 44 string[][3] letters_shift; 45 string[][3] letters_altgr; 46 string[][3] letters_shift_altgr; 47 } 48 49 enum LayoutChanger 50 { 51 Ctrl_Shift = Modifiers.Left_Ctrl | Modifiers.Left_Shift, 52 LeftAlt = Modifiers.Left_Alt, 53 RightAlt = Modifiers.Right_Alt, 54 CapsLock = Modifiers.CapsLock, 55 Shift_CapsLock = Modifiers.Left_Shift | Modifiers.CapsLock, 56 Alt_CapsLock = Modifiers.Left_Alt | Modifiers.CapsLock, 57 Both_Shift = Modifiers.Left_Shift | Modifiers.Right_Shift, 58 Both_Alt = Modifiers.Left_Alt | Modifiers.Right_Alt, 59 Both_Ctrl = Modifiers.Left_Ctrl | Modifiers.Right_Ctrl, 60 RightCtrl_RightShift = Modifiers.Right_Ctrl | Modifiers.Right_Shift, 61 Alt_Ctrl = Modifiers.Left_Alt | Modifiers.Left_Ctrl, 62 Alt_Shift = Modifiers.Left_Alt | Modifiers.Left_Shift, 63 Alt_Space = Modifiers.Left_Alt | Modifiers.Space, 64 Menu = Modifiers.Menu, 65 LeftWin = Modifiers.Left_Win, 66 Win_Space = Modifiers.Left_Win | Modifiers.Space, 67 RightWin = Modifiers.Right_Win, 68 LeftShift = Modifiers.Left_Shift, 69 RightShift = Modifiers.Right_Shift, 70 LeftCtrl = Modifiers.Left_Ctrl, 71 RightCtrl = Modifiers.Right_Ctrl, 72 ScrollLock = Modifiers.ScrollLock 73 } 74 75 struct ButtonPos 76 { 77 ushort i; 78 ushort pos; 79 } 80 81 class KeyBar_Buttons 82 { 83 private 84 SDL_Renderer *renderer; 85 86 bool input_mode; 87 88 string[] layout_names; 89 Layout[string] layouts; 90 Layout*[] layout_modes; 91 ssize_t mode; 92 LayoutChanger changer; 93 long last_change; 94 long last_shift; 95 96 string[][3] *letters; 97 98 KeyHandler[int] handlers; 99 KeyHandler[int] handlers_down; 100 KeyHandler[int] handlers_double; 101 SDL_Scancode[][3] *scans_cur; 102 SDL_Scancode[][3] scans; 103 SDL_Scancode[][3] scans_altgr; 104 ButtonPos[SDL_Scancode] buttonpos_by_scan; 105 ButtonPos[SDL_Scancode] buttonpos_by_scan_altgr; 106 107 string[] layout_changer_names; 108 LayoutChanger[] layout_changer_values; 109 110 bool keybar_settings_needed; 111 112 SDL_Rect[] buttons; 113 ssize_t pos; 114 this(GlobalState gs, SDL_Renderer *renderer, string start_cwd) 115 { 116 this.renderer = renderer; 117 buttons = 118 [SDL_Rect(0,0,32,32), SDL_Rect(32,0,32,32), SDL_Rect(64,0,32,32), SDL_Rect(96,0,32,32), SDL_Rect(128,0,32,32), SDL_Rect(160,0,32,32), 119 SDL_Rect(0,32,40,32), SDL_Rect(40,32,32,32), SDL_Rect(72,32,32,32), SDL_Rect(104,32,32,32), SDL_Rect(136,32,32,32), SDL_Rect(168,32,24,32), 120 SDL_Rect(0,64,48,32), SDL_Rect(48,64,32,32), SDL_Rect(80,64,32,32), SDL_Rect(112,64,32,32), SDL_Rect(144,64,32,32), SDL_Rect(176,64,16,32), 121 SDL_Rect(0,96,32,32), SDL_Rect(32,96,32,32), SDL_Rect(64,96,32,32), SDL_Rect(96,96,32,32), SDL_Rect(128,96,32,32), SDL_Rect(160,96,32,32), 122 SDL_Rect(0,128,48,16), SDL_Rect(48,128,32,16), SDL_Rect(80,128,32,16), SDL_Rect(112,128,32,16), SDL_Rect(144,128,48,16)]; 123 124 scans[0] = [SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, 125 SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, 126 SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, 127 SDL_SCANCODE_LSHIFT, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V, SDL_SCANCODE_B, 128 SDL_SCANCODE_LCTRL, SDL_SCANCODE_LALT, SDL_SCANCODE_LGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_SPACE 129 ]; 130 131 scans[1] = [SDL_SCANCODE_EQUALS, SDL_SCANCODE_MINUS, SDL_SCANCODE_0, SDL_SCANCODE_9, SDL_SCANCODE_8, SDL_SCANCODE_7, 132 SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_P, SDL_SCANCODE_O, SDL_SCANCODE_I, SDL_SCANCODE_U, 133 SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_SEMICOLON, SDL_SCANCODE_L, SDL_SCANCODE_K, SDL_SCANCODE_J, 0, 134 SDL_SCANCODE_RSHIFT, SDL_SCANCODE_SLASH, SDL_SCANCODE_PERIOD, SDL_SCANCODE_COMMA, SDL_SCANCODE_M, SDL_SCANCODE_N, 135 SDL_SCANCODE_RCTRL, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI, 0, 0 136 ]; 137 138 scans[2] = [SDL_SCANCODE_ESCAPE, SDL_SCANCODE_BACKSPACE, SDL_SCANCODE_KP_ENTER, SDL_SCANCODE_INSERT, SDL_SCANCODE_HOME, SDL_SCANCODE_PAGEUP, 139 SDL_SCANCODE_GRAVE, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_UP, SDL_SCANCODE_DELETE, SDL_SCANCODE_END, SDL_SCANCODE_PAGEDOWN, 140 SDL_SCANCODE_TAB, SDL_SCANCODE_LEFT, SDL_SCANCODE_DOWN, SDL_SCANCODE_RIGHT, SDL_SCANCODE_KP_MINUS, SDL_SCANCODE_KP_PLUS, 141 SDL_SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_KP_DIVIDE, SDL_SCANCODE_KP_MULTIPLY, SDL_SCANCODE_PRINTSCREEN, SDL_SCANCODE_SCROLLLOCK, SDL_SCANCODE_PAUSE, 142 0, 0, 0, 0, SDL_SCANCODE_RETURN 143 ]; 144 145 scans_altgr[0] = [SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4, SDL_SCANCODE_5, SDL_SCANCODE_6, 146 SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R, SDL_SCANCODE_T, SDL_SCANCODE_Y, 147 SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D, SDL_SCANCODE_F, SDL_SCANCODE_G, SDL_SCANCODE_H, 148 SDL_SCANCODE_LSHIFT, SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V, SDL_SCANCODE_B, 149 SDL_SCANCODE_LCTRL, SDL_SCANCODE_LALT, SDL_SCANCODE_LGUI, SDL_SCANCODE_MENU, SDL_SCANCODE_SPACE 150 ]; 151 152 scans_altgr[1] = [SDL_SCANCODE_EQUALS, SDL_SCANCODE_MINUS, SDL_SCANCODE_0, SDL_SCANCODE_9, SDL_SCANCODE_8, SDL_SCANCODE_7, 153 SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_P, SDL_SCANCODE_O, SDL_SCANCODE_I, SDL_SCANCODE_U, 154 SDL_SCANCODE_APOSTROPHE, SDL_SCANCODE_SEMICOLON, SDL_SCANCODE_L, SDL_SCANCODE_K, SDL_SCANCODE_J, SDL_SCANCODE_H, 155 SDL_SCANCODE_RSHIFT, SDL_SCANCODE_SLASH, SDL_SCANCODE_PERIOD, SDL_SCANCODE_COMMA, SDL_SCANCODE_M, SDL_SCANCODE_N, 156 SDL_SCANCODE_RCTRL, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI, 0, 0 157 ]; 158 159 scans_altgr[2] = [SDL_SCANCODE_KP_1, SDL_SCANCODE_KP_2, SDL_SCANCODE_KP_3, SDL_SCANCODE_KP_4, SDL_SCANCODE_KP_5, SDL_SCANCODE_KP_6, 160 SDL_SCANCODE_GRAVE, SDL_SCANCODE_BACKSLASH, SDL_SCANCODE_KP_7, SDL_SCANCODE_KP_8, SDL_SCANCODE_KP_9, SDL_SCANCODE_KP_0, 161 SDL_SCANCODE_F1, SDL_SCANCODE_F2, SDL_SCANCODE_F3, SDL_SCANCODE_F4, SDL_SCANCODE_F5, SDL_SCANCODE_F6, 162 SDL_SCANCODE_F7, SDL_SCANCODE_F8, SDL_SCANCODE_F9, SDL_SCANCODE_F10, SDL_SCANCODE_F11, SDL_SCANCODE_F12, 163 0, 0, 0, 0, SDL_SCANCODE_KP_PERIOD 164 ]; 165 166 for (ssize_t i=0; i < 3; i++) 167 { 168 for (ssize_t pos=0; pos < scans[i].length; pos++) 169 { 170 if (scans[i][pos] > 0) 171 buttonpos_by_scan[scans[i][pos]] = ButtonPos(cast(ushort) i, cast(ushort) pos); 172 if (scans_altgr[i][pos] > 0) 173 buttonpos_by_scan_altgr[scans_altgr[i][pos]] = ButtonPos(cast(ushort) i, cast(ushort) pos); 174 } 175 } 176 177 layout_changer_names = ["Ctrl + Shift", "Left Alt", "Right Alt", 178 "Caps Lock", "Left Shift + Caps Lock", "Left Alt + Caps Lock", 179 "Both Shift", "Both Alt", "Both Ctrl", "Right Ctrl + Right Shift", 180 "Left Alt + Left Ctrl", "Left Alt + Left Shift", "Left Alt + Space", 181 "Menu", "Left Win", "Left Win + Space", "Right Win", 182 "Left Shift", "Right Shift", "Left Ctrl", "Right Ctrl", 183 "Scroll Lock"]; 184 185 with (LayoutChanger) 186 { 187 layout_changer_values = [ Ctrl_Shift, LeftAlt, RightAlt, 188 CapsLock, Shift_CapsLock, Alt_CapsLock, 189 Both_Shift, Both_Alt, Both_Ctrl, RightCtrl_RightShift, 190 Alt_Ctrl, Alt_Shift, Alt_Space, 191 Menu, LeftWin, Win_Space, RightWin, 192 LeftShift, RightShift, LeftCtrl, RightCtrl, 193 ScrollLock]; 194 } 195 196 assert(layout_changer_names.length == layout_changer_values.length); 197 198 read_layouts(gs, start_cwd); 199 SDL_StopTextInput(); 200 } 201 202 long last_buttons_cache_use; 203 Texture_Tick[ButtonParms] button_cache; 204 205 auto 206 get_button_from_cache(SDL_Rect rect, SDL_Color color) 207 { 208 auto butparm = ButtonParms(rect, color); 209 auto tt = butparm in button_cache; 210 if (tt) 211 { 212 tt.tick = SDL_GetTicks(); 213 last_buttons_cache_use = SDL_GetTicks(); 214 } 215 else 216 { 217 SDL_Surface* surface = SDL_CreateRGBSurface(0, 218 rect.w, 219 rect.h, 220 32, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 221 222 SDL_Rect dst = SDL_Rect(0,0,rect.w,rect.h); 223 SDL_FillRect(surface, &dst, 0xff000000); 224 225 dst.x += 1; 226 dst.y += 1; 227 dst.w -= 2; 228 dst.h -= 2; 229 230 SDL_FillRect(surface, &dst, 231 (color.a<<24) | (color.r<<16) | 232 (color.g<<8) | color.b); 233 234 auto texture = 235 SDL_CreateTextureFromSurface(renderer, surface); 236 237 button_cache[butparm] = Texture_Tick(rect.w, rect.h, [], texture, SDL_GetTicks()); 238 last_buttons_cache_use = SDL_GetTicks(); 239 tt = butparm in button_cache; 240 } 241 242 return tt; 243 } 244 245 void 246 read_layouts(GlobalState gs, string start_cwd) 247 { 248 string layouts_dir = start_cwd~SL~"layouts"~SL; 249 if (!exists(layouts_dir)) 250 { 251 layouts_dir = "/usr/share/unde/layouts/"; 252 if (!exists(layouts_dir)) 253 { 254 new Exception("Not found .layouts or /usr/share/unde/layouts/"); 255 } 256 } 257 258 foreach(filename; dirEntries(layouts_dir, SpanMode.breadth)) 259 { 260 if (filename.isDir) continue; 261 262 File file = File(filename); 263 264 Layout layout; 265 ssize_t sl2 = filename.lastIndexOf(SL); 266 ssize_t sl1 = filename[0..sl2].lastIndexOf(SL); 267 layout.short_name = filename[sl1+1..sl2]~"("~filename[sl2+1..$]~")"; 268 string[][3] *letters; 269 ssize_t i = 0; 270 271 foreach(line; file.byLine()) 272 { 273 if (line.startsWith("Name=")) 274 layout.name = line[5..$].idup(); 275 if (line == "Letters:") 276 { 277 i = 0; 278 letters = &layout.letters; 279 } 280 if (line == "Letters_Shift:") 281 { 282 i = 0; 283 letters = &layout.letters_shift; 284 } 285 if (line == "Letters_Altgr:") 286 { 287 i = 0; 288 letters = &layout.letters_altgr; 289 } 290 if (line == "Letters_Shift_Altgr:") 291 { 292 i = 0; 293 letters = &layout.letters_shift_altgr; 294 } 295 if (line == "[]") 296 i++; 297 if (line[0] == '[' && line [$-1] == ']') 298 { 299 string chr; 300 bool backslash; 301 int state = 0; 302 line = line[1..$-1]; 303 foreach (c; line) 304 { 305 if (state == 0) 306 { 307 if (c == '\"') 308 { 309 state = 1; 310 chr = ""; 311 } 312 } 313 else if (state == 1) 314 { 315 if (c == '\\' && !backslash) 316 { 317 backslash = true; 318 } 319 else if (c == '\"' && !backslash) 320 { 321 (*letters)[i] ~= chr; 322 state = 0; 323 } 324 else 325 { 326 chr ~= c; 327 backslash = false; 328 } 329 } 330 } 331 i++; 332 } 333 } 334 335 layout_names ~= layout.name ~ " - " ~ layout.short_name; 336 layouts[layout.short_name] = layout; 337 } 338 339 sort!("a < b")(layout_names); 340 load_keybar_settings(gs, this); 341 } 342 } 343 344 void update_letters(GlobalState gs) 345 { 346 if (gs.keybar.input_mode) 347 { 348 if (gs.alt_gr && gs.shift) 349 gs.keybar.letters = &gs.keybar.layout_modes[gs.keybar.mode].letters_shift_altgr; 350 else if (gs.alt_gr) 351 gs.keybar.letters = &gs.keybar.layout_modes[gs.keybar.mode].letters_altgr; 352 else if (gs.shift) 353 gs.keybar.letters = &gs.keybar.layout_modes[gs.keybar.mode].letters_shift; 354 else 355 gs.keybar.letters = &gs.keybar.layout_modes[gs.keybar.mode].letters; 356 } 357 else 358 { 359 if (gs.alt_gr && gs.shift) 360 gs.keybar.letters = &gs.keybar.layouts["us(basic)"].letters_shift_altgr; 361 else if (gs.alt_gr) 362 gs.keybar.letters = &gs.keybar.layouts["us(basic)"].letters_altgr; 363 else if (gs.shift) 364 gs.keybar.letters = &gs.keybar.layouts["us(basic)"].letters_shift; 365 else 366 gs.keybar.letters = &gs.keybar.layouts["us(basic)"].letters; 367 } 368 } 369 370 void 371 draw_keybar(GlobalState gs) 372 { 373 ushort[] attrs; 374 for (ssize_t z=0; z<16; z++) 375 attrs ~= Attr.Bold | Attr.Color; 376 377 SDL_Rect full_rect; 378 full_rect.x = gs.screen.w; 379 full_rect.y = gs.screen.h - 32*4-16; 380 full_rect.w = 32*6; 381 full_rect.h = 32*4+16; 382 383 if (gs.mouse_screen_x > full_rect.x && 384 gs.mouse_screen_x < full_rect.x + full_rect.w && 385 gs.mouse_screen_y > full_rect.y && 386 gs.mouse_screen_y < full_rect.y + full_rect.h) 387 { 388 gs.keybar.pos = get_position_by_chars( 389 gs.mouse_screen_x - full_rect.x, 390 gs.mouse_screen_y - full_rect.y, gs.keybar.buttons); 391 } 392 else gs.keybar.pos = -1; 393 394 foreach(i, but; gs.keybar.buttons) 395 { 396 SDL_Color color = SDL_Color(0xFF, 0xFF, 0xFF, 0xFF); 397 if (gs.keybar.pos == i) 398 { 399 color = SDL_Color(0x80, 0xFF, 0xFF, 0xFF); 400 } 401 auto tt = gs.keybar.get_button_from_cache(but, color); 402 if (!tt && !tt.texture) 403 { 404 throw new Exception("can't create text_surface: "~ 405 SDL_GetError().fromStringz().idup()); 406 } 407 408 SDL_Rect rect; 409 rect.x = but.x + gs.screen.w; 410 rect.y = but.y + gs.screen.h - 32*4-16; 411 rect.w = but.w; 412 rect.h = but.h; 413 414 int r = SDL_RenderCopy(gs.renderer, tt.texture, null, &rect); 415 if (r < 0) 416 { 417 writefln( 418 "draw_keybar(): error while render copy: %s", 419 SDL_GetError().fromStringz() ); 420 } 421 422 int[3] x = [2, 18, 2]; 423 int[3] y = [0, 7, 22]; 424 int[3] xp = [0, 16, 0]; 425 int[3] yp = [0, 8, 16]; 426 SDL_Color[3] bright = [SDL_Color(0x00, 0x00, 0x00, 0xFF), 427 SDL_Color(0xFF, 0x00, 0x00, 0xFF), 428 SDL_Color(0x80, 0x80, 0x80, 0xFF) 429 ]; 430 SDL_Color[3] unbright = [SDL_Color(0xC0, 0xC0, 0xC0, 0xFF), 431 SDL_Color(0xFF, 0xC0, 0xC0, 0xFF), 432 SDL_Color(0xE0, 0xE0, 0xE0, 0xFF) 433 ]; 434 435 string description = ""; 436 437 update_letters(gs); 438 439 if (gs.alt_gr) 440 gs.keybar.scans_cur = &gs.keybar.scans_altgr; 441 else 442 gs.keybar.scans_cur = &gs.keybar.scans; 443 444 for (ssize_t j=0; j < 3; j++) 445 { 446 bool sameleft = false; 447 if (j==1 && (*gs.keybar.letters)[j][i] == (*gs.keybar.letters)[0][i]) 448 sameleft = true; 449 KeyHandler* key_handler = (*gs.keybar.scans_cur)[j][i] in gs.keybar.handlers; 450 KeyHandler* key_handler_down = (*gs.keybar.scans_cur)[j][i] in gs.keybar.handlers_down; 451 KeyHandler* key_handler_double = (*gs.keybar.scans_cur)[j][i] in gs.keybar.handlers_double; 452 if (key_handler || key_handler_down || key_handler_double) 453 { 454 if (gs.keybar.pos == i && (*gs.keybar.letters)[j][i] > "") 455 { 456 if (key_handler && key_handler.description > "") 457 description ~= (*gs.keybar.letters)[j][i]~" - "~key_handler.description ~ "\n"; 458 if (key_handler_down && key_handler_down.description > "") 459 description ~= "Hold " ~ (*gs.keybar.letters)[j][i]~" - "~key_handler_down.description ~ "\n"; 460 if (key_handler_double && key_handler_double.description > "") 461 description ~= "Double " ~ (*gs.keybar.letters)[j][i]~" - "~key_handler_double.description ~ "\n"; 462 } 463 464 if (!key_handler && key_handler_down) 465 key_handler = key_handler_down; 466 467 if (!key_handler && key_handler_double) 468 key_handler = key_handler_double; 469 470 if ( key_handler.icon.endsWith(".png") ) 471 { 472 string image_file = gs.start_cwd~SL~"images"~SL~key_handler.icon; 473 if (!exists(image_file)) 474 { 475 image_file = "/usr/share/unde/images/"~key_handler.icon; 476 if (!exists(image_file)) 477 { 478 new Exception("Not found .images or /usr/share/unde/images/"); 479 } 480 } 481 482 auto st = get_image_from_cache(gs, image_file); 483 484 if (st) 485 { 486 SDL_Rect dst; 487 dst.x = rect.x + xp[j]; 488 dst.y = rect.y + yp[j]; 489 if (j == 2 && i >= 6*4) 490 { 491 dst.x+=24; 492 dst.y-=16; 493 } 494 dst.w = st.w; 495 dst.h = st.h; 496 497 r = SDL_RenderCopy(gs.renderer, st.texture, null, &dst); 498 if (r < 0) 499 { 500 writefln( "draw_keybar() 2: Error while render copy: %s", 501 SDL_GetError().fromStringz() ); 502 } 503 } 504 else 505 { 506 writefln("Can't load %s: %s", 507 image_file, 508 IMG_GetError().fromStringz()); 509 } 510 } 511 else 512 { 513 int fontsize = 8; 514 if (key_handler.icon.walkLength() > 1 && i < 24 || 515 j==2 && i == 28) 516 fontsize = 6; 517 if (key_handler.icon == "Menu" || 518 key_handler.icon == "Spc") 519 fontsize = 7; 520 tt = gs.text_viewer.font.get_line_from_cache(key_handler.icon, 521 fontsize, 48, 20, bright[j], attrs); 522 if (!tt && !tt.texture) 523 { 524 throw new Exception("Can't create text_surface: "~ 525 TTF_GetError().fromStringz().idup()); 526 } 527 528 SDL_Rect dst; 529 dst.x = rect.x + x[j]; 530 if ( j == 1 && i == 11 ) 531 dst.x -= 8; 532 dst.y = rect.y + y[j]; 533 if ( key_handler.icon.walkLength == 1 && j == 2 ) 534 dst.y -= 7; 535 if ( (*gs.keybar.letters)[j][i] == "Enter" && i >= 24 ) 536 { 537 dst.x = rect.x+24; 538 dst.y = rect.y+3; 539 } 540 dst.w = tt.w; 541 dst.h = tt.h; 542 543 r = SDL_RenderCopy(gs.renderer, tt.texture, null, &dst); 544 if (r < 0) 545 { 546 writefln( "draw_keybar() 3: Error while render copy: %s", 547 SDL_GetError().fromStringz() ); 548 } 549 550 } 551 } 552 else 553 { 554 if (sameleft) continue; 555 int fontsize = 8; 556 if ((*gs.keybar.letters)[j][i].walkLength() > 1 && i < 24 || 557 j==2 && i == 28) 558 fontsize = 6; 559 if ((*gs.keybar.letters)[j][i] == "Menu" || 560 (*gs.keybar.letters)[j][i] == "Spc") 561 fontsize = 7; 562 tt = gs.text_viewer.font.get_line_from_cache((*gs.keybar.letters)[j][i], 563 fontsize, 48, 20, (gs.keybar.input_mode?bright[j]:unbright[j]), attrs); 564 if (!tt && !tt.texture) 565 { 566 throw new Exception("Can't create text_surface: "~ 567 TTF_GetError().fromStringz().idup()); 568 } 569 570 SDL_Rect dst; 571 dst.x = rect.x + x[j]; 572 if ( j == 1 && i == 11 ) 573 dst.x -= 8; 574 dst.y = rect.y + y[j]; 575 if ( (*gs.keybar.letters)[j][i].walkLength == 1 && j == 2 ) 576 dst.y -= 7; 577 if ( (*gs.keybar.letters)[j][i] == "Enter" && i >= 24 ) 578 { 579 dst.x = rect.x+24; 580 dst.y = rect.y+3; 581 } 582 dst.w = tt.w; 583 dst.h = tt.h; 584 585 r = SDL_RenderCopy(gs.renderer, tt.texture, null, &dst); 586 if (r < 0) 587 { 588 writefln( "draw_keybar() 4: Error while render copy: %s", 589 SDL_GetError().fromStringz() ); 590 } 591 } 592 } 593 594 if (description != "") 595 { 596 description = description[0..$-1]; 597 598 int fontsize = 8; 599 int line_height = cast(int)(round(SQRT2^^fontsize)*1.2); 600 tt = gs.text_viewer.font.get_line_from_cache(description, 601 fontsize, 32*6, line_height, SDL_Color(0xFF, 0xFF, 0xFF, 0xFF)); 602 if (!tt && !tt.texture) 603 { 604 throw new Exception("Can't create text_surface: "~ 605 TTF_GetError().fromStringz().idup()); 606 } 607 608 /* Render black background */ 609 SDL_Rect dst; 610 dst.x = gs.screen.w; 611 dst.y = gs.screen.h - 32*4-16 - tt.h; 612 dst.w = tt.w; 613 dst.h = tt.h; 614 615 r = SDL_RenderCopy(gs.renderer, gs.texture_black, null, &dst); 616 if (r < 0) 617 { 618 writefln( "draw_keybar(), 5: Error while render copy: %s", 619 SDL_GetError().fromStringz() ); 620 } 621 622 /* Render description of buttons */ 623 r = SDL_RenderCopy(gs.renderer, tt.texture, null, &dst); 624 if (r < 0) 625 { 626 writefln( "draw_keybar() 6: Error while render copy: %s", 627 SDL_GetError().fromStringz() ); 628 } 629 } 630 } 631 } 632 633 void 634 save_keybar_settings(GlobalState gs) 635 { 636 with(gs.keybar) 637 { 638 Dbt key, data; 639 string keybar_settings_str = "keybar_settings"; 640 key = keybar_settings_str; 641 string data_str = ""; 642 643 data_str ~= (cast(char*)&changer)[0..changer.sizeof]; 644 foreach(layout_mode; layout_modes) 645 { 646 data_str ~= layout_mode.short_name ~ "\0"; 647 } 648 649 data = data_str; 650 651 auto res = gs.db_marks.put(null, &key, &data); 652 if (res != 0) 653 { 654 throw new Exception("Oh, no, can't to write keybar settings"); 655 } 656 } 657 } 658 659 void 660 load_keybar_settings(GlobalState gs, KeyBar_Buttons keybar) 661 { 662 with(keybar) 663 { 664 Dbt key, data; 665 string keybar_settings_str = "keybar_settings"; 666 key = keybar_settings_str; 667 668 auto res = gs.db_marks.get(null, &key, &data); 669 if (res == 0) 670 { 671 string data_str = data.to!(string); 672 changer = *cast(LayoutChanger*)(data_str[0..changer.sizeof].ptr); 673 data_str = data_str[changer.sizeof..$]; 674 ssize_t pos; 675 while ( (pos = data_str.indexOf("\0")) >= 0 ) 676 { 677 layout_modes ~= &layouts[data_str[0..pos]]; 678 data_str = data_str[pos+1..$]; 679 } 680 } 681 else 682 { 683 layout_modes ~= &layouts["us(basic)"]; 684 version (Posix) 685 { 686 string lc_messages = setlocale(LC_MESSAGES, null).fromStringz().idup(); 687 writefln("lc_messages=%s", lc_messages); 688 if (lc_messages == "" || lc_messages == "C") 689 lc_messages = environment["LANG"]; 690 writefln("lc_messages=%s", lc_messages); 691 if (lc_messages.length > 3 && lc_messages[0..3] == "ru_") 692 { 693 layout_modes ~= &layouts["ru(winkeys)"]; 694 } 695 } 696 else 697 version (Windows) 698 { 699 auto lang = 0xFF & GetUserDefaultUILanguage(); 700 if (lang == LANG_RUSSIAN) 701 { 702 layout_modes ~= &layouts["ru(winkeys)"]; 703 } 704 } 705 changer = LayoutChanger.LeftWin; 706 keybar_settings_needed = true; 707 } 708 } 709 }