Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. #include <memory>
  21. #include <stdlib.h>
  22. #include <math.h>
  23. #include <string.h>
  24. #include "physfsx.h"
  25. #include "maths.h"
  26. #include "pstypes.h"
  27. #include "gr.h"
  28. #include "key.h"
  29. #include "ui.h"
  30. #include "u_mem.h"
  31. #include "func.h"
  32. #include "dxxerror.h"
  33.  
  34. #include "compiler-range_for.h"
  35. #include "d_range.h"
  36. #include <memory>
  37.  
  38. namespace dcx {
  39.  
  40. #define MAX_NUM_PADS 20
  41.  
  42. static std::array<std::unique_ptr<UI_GADGET_BUTTON>, 17> Pad;
  43. static std::array<std::unique_ptr<UI_KEYPAD>, MAX_NUM_PADS> KeyPad;
  44. static int active_pad;
  45.  
  46. static int desc_x, desc_y;
  47.  
  48. static std::array<int, 17> HotKey, HotKey1;
  49.  
  50. int ui_pad_get_current()
  51. {
  52.         return active_pad;
  53. }
  54.  
  55. void ui_pad_init()
  56. {
  57.         KeyPad = {};
  58.         active_pad = 0;
  59. }
  60.  
  61. void ui_pad_close()
  62. {
  63.         KeyPad = {};
  64. }
  65.  
  66. typedef PHYSFSX_gets_line_t<100>::line_t keypad_input_line_t;
  67.  
  68. static keypad_input_line_t::const_iterator find_fake_comma(keypad_input_line_t::const_iterator i, keypad_input_line_t::const_iterator e)
  69. {
  70.         auto is_fake_comma = [](char c) {
  71.                 return !c || static_cast<uint8_t>(c) == 179;
  72.         };
  73.         return std::find_if(i, e, is_fake_comma);
  74. }
  75.  
  76. template <bool append, char eor>
  77. static keypad_input_line_t::const_iterator set_row(keypad_input_line_t::const_iterator i, const keypad_input_line_t::const_iterator e, UI_KEYPAD::buttontext_element_t &r)
  78. {
  79.         const auto oe = r.end();
  80.         auto ob = r.begin();
  81.         if (append)
  82.                 ob = std::find(ob, oe, 0);
  83.         auto comma0 = find_fake_comma(i, e);
  84.         if (comma0 == e)
  85.                 /* Start not found */
  86.                 return comma0;
  87.         const auto comma1 = find_fake_comma(++ comma0, e);
  88.         std::size_t id = std::distance(comma0, comma1);
  89.         std::size_t od = std::distance(ob, oe);
  90.         if (!od)
  91.                 /* Output buffer full */
  92.                 return comma1;
  93.         -- od;
  94.         std::size_t md = std::min(id, od);
  95.         std::copy_n(comma0, md, ob);
  96.         std::advance(ob, md);
  97.         assert(ob != oe);
  98.         if (ob == oe)
  99.                 -- ob;
  100.         if (eor)
  101.         {
  102.                 /* Add EOR if room */
  103.                 auto on = std::next(ob);
  104.                 if (on != oe)
  105.                         *ob++ = eor;
  106.         }
  107.         *ob = 0;
  108.         return comma1;
  109. }
  110.  
  111. template <bool append, char eor, typename... T>
  112. static keypad_input_line_t::const_iterator set_row(keypad_input_line_t::const_iterator i, const keypad_input_line_t::const_iterator e, UI_KEYPAD::buttontext_element_t &r, T &... t)
  113. {
  114.         return set_row<append, eor>(set_row<append, eor>(i, e, r), e, t...);
  115. }
  116.  
  117. static void set_short_row(keypad_input_line_t::const_iterator i, const keypad_input_line_t::const_iterator e, UI_KEYPAD::buttontext_element_t &r)
  118. {
  119.         typedef std::reverse_iterator<keypad_input_line_t::const_iterator> reverse_iterator;
  120.         const auto oe = r.end();
  121.         auto ob = std::find(r.begin(), oe, 0);
  122.         std::size_t od = std::distance(ob, oe);
  123.         if (!od)
  124.                 return;
  125.         -- od;
  126.         auto ie = std::find(i, e, 0);
  127.         auto ri = reverse_iterator(i);
  128.         auto comma0 = std::find(reverse_iterator(ie), ri, 179);
  129.         if (comma0 == ri)
  130.                 return;
  131.         auto comma1 = std::find(++ comma0, ri, 180);
  132.         if (comma1 == ri)
  133.                 return;
  134.         auto bcomma1 = comma1.base();
  135.         std::size_t id = std::distance(comma0.base(), bcomma1);
  136.         std::size_t md = std::min(id, od);
  137.         std::copy_n(bcomma1, md, ob);
  138.         std::advance(ob, md);
  139.         assert(ob != oe);
  140.         if (ob == oe)
  141.                 -- ob;
  142.         auto on = std::next(ob);
  143.         if (on != oe)
  144.                 *ob++ = '\n';
  145.         *ob = 0;
  146. }
  147.  
  148. static std::unique_ptr<UI_GADGET_BUTTON> ui_create_pad_gadget(UI_DIALOG &dlg, uint_fast32_t x, uint_fast32_t y, uint_fast32_t w, uint_fast32_t h, const grs_font &font)
  149. {
  150.         auto r = ui_add_gadget_button(&dlg, x, y, w, h, nullptr, nullptr);
  151.         r->canvas->cv_font = &font;
  152.         return r;
  153. }
  154.  
  155. void ui_pad_activate(UI_DIALOG &dlg, uint_fast32_t x, uint_fast32_t y)
  156. {
  157.         const uint_fast32_t bw = 56;
  158.         const uint_fast32_t bh = 30;
  159.         const uint_fast32_t x5 = x + 5;
  160.         const uint_fast32_t y20 = y + 20;
  161.         const auto &font = *ui_small_font.get();
  162.         const auto fx = [=](uint_fast32_t col) {
  163.                 return x5 + (bw * col);
  164.         };
  165.         const auto fy = [=](uint_fast32_t row) {
  166.                 return y20 + (bh * row);
  167.         };
  168.         const auto fw = [=](uint_fast32_t w) {
  169.                 return bw * w;
  170.         };
  171.         const auto fh = [=](uint_fast32_t h) {
  172.                 return bh * h;
  173.         };
  174.         const auto ui_add_pad_gadget = [&dlg, &font](uint_fast32_t n, uint_fast32_t gx, uint_fast32_t gy, uint_fast32_t w, uint_fast32_t h) {
  175.                 Pad[n] = ui_create_pad_gadget(dlg, gx, gy, w, h, font);
  176.         };
  177.  
  178.         int w,h,row,col, n;
  179.  
  180.         desc_x = x+2;
  181.         desc_y = y-17;
  182.  
  183.         n=0; row = 0; col = 0; w = 1; h = 1;
  184.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  185.         n=1; row = 0; col = 1; w = 1; h = 1;
  186.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  187.         n=2; row = 0; col = 2; w = 1; h = 1;
  188.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  189.         n=3; row = 0; col = 3; w = 1; h = 1;
  190.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  191.         n=4; row = 1; col = 0; w = 1; h = 1;
  192.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  193.         n=5; row = 1; col = 1; w = 1; h = 1;
  194.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  195.         n=6; row = 1; col = 2; w = 1; h = 1;
  196.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  197.         n=7; row = 1; col = 3; w = 1; h = 2;
  198.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  199.         n=8; row = 2; col = 0; w = 1; h = 1;
  200.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  201.         n=9; row = 2; col = 1; w = 1; h = 1;
  202.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  203.         n=10; row = 2; col = 2; w = 1; h = 1;
  204.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  205.         n=11; row = 3; col = 0; w = 1; h = 1;
  206.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  207.         n=12; row = 3; col = 1; w = 1; h = 1;
  208.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  209.         n=13; row = 3; col = 2; w = 1; h = 1;
  210.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  211.         n=14; row = 3; col = 3; w = 1; h = 2;
  212.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  213.         n=15; row = 4; col = 0; w = 2; h = 1;
  214.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  215.         n=16; row = 4; col = 2; w = 1; h = 1;
  216.         ui_add_pad_gadget(n, fx(col), fy(row), fw(w), fh(h));
  217.  
  218.         HotKey[0] = KEY_CTRLED + KEY_NUMLOCK;
  219.         HotKey[1] = KEY_CTRLED + KEY_PADDIVIDE;
  220.         HotKey[2] = KEY_CTRLED + KEY_PADMULTIPLY;
  221.         HotKey[3] = KEY_CTRLED + KEY_PADMINUS;
  222.         HotKey[4] = KEY_CTRLED + KEY_PAD7;
  223.         HotKey[5] = KEY_CTRLED + KEY_PAD8;
  224.         HotKey[6] = KEY_CTRLED + KEY_PAD9;
  225.         HotKey[7] = KEY_CTRLED + KEY_PADPLUS;
  226.         HotKey[8] = KEY_CTRLED + KEY_PAD4;
  227.         HotKey[9] = KEY_CTRLED + KEY_PAD5;
  228.         HotKey[10] = KEY_CTRLED + KEY_PAD6;
  229.         HotKey[11] = KEY_CTRLED + KEY_PAD1;
  230.         HotKey[12] = KEY_CTRLED + KEY_PAD2;
  231.         HotKey[13] = KEY_CTRLED + KEY_PAD3;
  232.         HotKey[14] = KEY_CTRLED + KEY_PADENTER;
  233.         HotKey[15] = KEY_CTRLED + KEY_PAD0;
  234.         HotKey[16] = KEY_CTRLED + KEY_PADPERIOD;
  235.  
  236.         HotKey1[0] = KEY_SHIFTED + KEY_CTRLED + KEY_NUMLOCK;
  237.         HotKey1[1] = KEY_SHIFTED + KEY_CTRLED + KEY_PADDIVIDE;
  238.         HotKey1[2] = KEY_SHIFTED + KEY_CTRLED + KEY_PADMULTIPLY;
  239.         HotKey1[3] = KEY_SHIFTED + KEY_CTRLED + KEY_PADMINUS;
  240.         HotKey1[4] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD7;
  241.         HotKey1[5] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD8;
  242.         HotKey1[6] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD9;
  243.         HotKey1[7] = KEY_SHIFTED + KEY_CTRLED + KEY_PADPLUS;
  244.         HotKey1[8] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD4;
  245.         HotKey1[9] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD5;
  246.         HotKey1[10] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD6;
  247.         HotKey1[11] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD1;
  248.         HotKey1[12] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD2;
  249.         HotKey1[13] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD3;
  250.         HotKey1[14] = KEY_SHIFTED + KEY_CTRLED + KEY_PADENTER;
  251.         HotKey1[15] = KEY_SHIFTED + KEY_CTRLED + KEY_PAD0;
  252.         HotKey1[16] = KEY_SHIFTED + KEY_CTRLED + KEY_PADPERIOD;
  253.  
  254.         active_pad = 0;
  255.  
  256. }
  257.  
  258.  
  259. void ui_pad_deactivate()
  260. {
  261.         range_for (auto &i, Pad)
  262.         {
  263.                 i->text.clear();
  264.         }
  265. }
  266.  
  267. void ui_pad_draw(UI_DIALOG *dlg, int x, int y)
  268. {
  269.         int bh, bw;
  270.        
  271.         bw = 56; bh = 30;
  272.        
  273.         ui_dialog_set_current_canvas( dlg );
  274.         ui_draw_box_in(*grd_curcanv, x, y, x+(bw * 4)+10 + 200, y+(bh * 5)+45);
  275.  
  276.         gr_set_default_canvas();
  277.         auto &canvas = *grd_curcanv;
  278.         const auto color = CWHITE;
  279.         gr_urect(canvas, desc_x, desc_y, desc_x+ 56*4-1, desc_y+15, color);
  280.         gr_set_fontcolor(canvas, CBLACK, CWHITE);
  281.         gr_ustring(canvas, *canvas.cv_font, desc_x, desc_y, KeyPad[active_pad]->description.data());
  282. }
  283.  
  284. static void ui_pad_set_active( int n )
  285. {
  286.         int np;
  287.         const char * name;
  288.        
  289.  
  290.         range_for (const int i, xrange(17u))
  291.         {
  292.                 Pad[i]->text = KeyPad[n]->buttontext[i].data();
  293.                 Pad[i]->status = 1;
  294.                 Pad[i]->user_function = NULL;
  295.                 Pad[i]->dim_if_no_function = 1;
  296.                 Pad[i]->hotkey = -1;
  297.                                
  298.                 for (int j=0; j< KeyPad[n]->numkeys; j++ )
  299.                 {
  300.                         if (HotKey[i] == KeyPad[n]->keycode[j] )
  301.                         {
  302.                                 Pad[i]->hotkey =  HotKey[i];
  303.                                 Pad[i]->user_function = func_nget( KeyPad[n]->function_number[j], &np, &name );
  304.                         }
  305.                         if (HotKey1[i] == KeyPad[n]->keycode[j] )
  306.                         {
  307.                                 Pad[i]->hotkey1 =  HotKey1[i];
  308.                                 Pad[i]->user_function1 = func_nget( KeyPad[n]->function_number[j], &np, &name );
  309.                         }
  310.                 }
  311.         }
  312.  
  313.         active_pad = n;
  314. }
  315.  
  316. void ui_pad_goto(int n)
  317. {
  318.         if ( KeyPad[n] != NULL )
  319.                 ui_pad_set_active(n);
  320. }
  321.  
  322. void ui_pad_goto_next()
  323. {
  324.         int i, si;
  325.  
  326.         i = active_pad + 1;
  327.         si = i;
  328.        
  329.         while( KeyPad[i]==NULL )
  330.         {
  331.                 i++;
  332.                 if (i >= MAX_NUM_PADS)
  333.                         i = 0;
  334.                 if (i == si )
  335.                         break;
  336.         }
  337.         ui_pad_set_active(i);
  338. }
  339.  
  340. void ui_pad_goto_prev()
  341. {
  342.         int i;
  343.  
  344.         if (active_pad == -1 )
  345.                 active_pad = MAX_NUM_PADS;
  346.        
  347.         i = active_pad - 1;
  348.         if (i<0) i= MAX_NUM_PADS - 1;
  349.        
  350.         while( KeyPad[i]==NULL )
  351.         {
  352.                 i--;
  353.                 if (i < 0)
  354.                         i = MAX_NUM_PADS-1;
  355.                 if (i == active_pad )
  356.                         break;
  357.         }
  358.         ui_pad_set_active(i);
  359. }
  360.  
  361. UI_KEYPAD::UI_KEYPAD() :
  362.         numkeys(0)
  363. {
  364.         description.front() = 0;
  365.         range_for (auto &i, buttontext)
  366.                 i[0] = 0;
  367. }
  368.  
  369. int ui_pad_read( int n, const char * filename )
  370. {
  371.         int linenumber = 0;
  372.         int keycode, functionnumber;
  373.  
  374.         auto infile = PHYSFSX_openReadBuffered(filename);
  375.         if (!infile) {
  376.                 Warning( "Could not find %s\n", filename );
  377.                 return 0;
  378.         }
  379.         auto &kpn = *(KeyPad[n] = std::make_unique<UI_KEYPAD>());
  380.  
  381.         PHYSFSX_gets_line_t<100> buffer;
  382.         while ( linenumber < 22)
  383.         {
  384.                 PHYSFSX_fgets( buffer, infile );
  385.  
  386.                 auto &line = buffer.line();
  387.                 const auto lb = line.begin();
  388.                 const auto le = line.end();
  389.                 switch( linenumber+1 )
  390.                 {
  391.                 case 1:
  392.                         kpn.description.copy_if(line);
  393.                         break;
  394.                 //===================== ROW 0 ==============================
  395.                 case 3:
  396.                         set_row<false, '\n'>(lb, le, kpn.buttontext[0], kpn.buttontext[1], kpn.buttontext[2], kpn.buttontext[3]);
  397.                         break;
  398.                 case 4:
  399.                         set_row<true, '\n'>(lb, le, kpn.buttontext[0], kpn.buttontext[1], kpn.buttontext[2], kpn.buttontext[3]);
  400.                         break;
  401.                 case 5:
  402.                         set_row<true, 0>(lb, le, kpn.buttontext[0], kpn.buttontext[1], kpn.buttontext[2], kpn.buttontext[3]);
  403.                         break;
  404.                 //===================== ROW 1 ==============================
  405.                 case 7:
  406.                         set_row<false, '\n'>(lb, le, kpn.buttontext[4], kpn.buttontext[5], kpn.buttontext[6], kpn.buttontext[7]);
  407.                         break;
  408.                 case 8:
  409.                         set_row<true, '\n'>(lb, le, kpn.buttontext[4], kpn.buttontext[5], kpn.buttontext[6], kpn.buttontext[7]);
  410.                         break;
  411.                 case 9:
  412.                         set_row<true, '\n'>(set_row<true, 0>(lb, le, kpn.buttontext[4], kpn.buttontext[5], kpn.buttontext[6]), le, kpn.buttontext[7]);
  413.                         break;
  414.                 case 10:
  415.                         set_short_row(lb, le, kpn.buttontext[7]);
  416.                         break;
  417.                 //======================= ROW 2 ==============================
  418.                 case 11:
  419.                         set_row<true, '\n'>(set_row<false, '\n'>(lb, le, kpn.buttontext[8], kpn.buttontext[9], kpn.buttontext[10]), le, kpn.buttontext[7]);
  420.                         break;
  421.                 case 12:
  422.                         set_row<true, '\n'>(lb, le, kpn.buttontext[8], kpn.buttontext[9], kpn.buttontext[10], kpn.buttontext[7]);
  423.                         break;
  424.                 case 13:
  425.                         set_row<true, 0>(lb, le, kpn.buttontext[8], kpn.buttontext[9], kpn.buttontext[10], kpn.buttontext[7]);
  426.                         break;
  427.                 // ====================== ROW 3 =========================
  428.                 case 15:
  429.                         set_row<false, '\n'>(lb, le, kpn.buttontext[11], kpn.buttontext[12], kpn.buttontext[13], kpn.buttontext[14]);
  430.                         break;
  431.                 case 16:
  432.                         set_row<true, '\n'>(lb, le, kpn.buttontext[11], kpn.buttontext[12], kpn.buttontext[13], kpn.buttontext[14]);
  433.                         break;
  434.                 case 17:
  435.                         set_row<true, '\n'>(set_row<true, 0>(lb, le, kpn.buttontext[11], kpn.buttontext[12], kpn.buttontext[13]), le, kpn.buttontext[14]);
  436.                         break;
  437.                 case 18:
  438.                         set_short_row(lb, le, kpn.buttontext[14]);
  439.                         break;
  440.                 //======================= ROW 4 =========================
  441.                 case 19:
  442.                         set_row<true, '\n'>(set_row<false, '\n'>(lb, le, kpn.buttontext[15], kpn.buttontext[16]), le, kpn.buttontext[14]);
  443.                         break;
  444.                 case 20:
  445.                         set_row<true, '\n'>(lb, le, kpn.buttontext[15], kpn.buttontext[16], kpn.buttontext[14]);
  446.                         break;
  447.                 case 21:
  448.                         set_row<true, 0>(lb, le, kpn.buttontext[15], kpn.buttontext[16], kpn.buttontext[14]);
  449.                         break;
  450.                 }
  451.                                                                                
  452.                 linenumber++;  
  453.         }
  454.  
  455.         // Get the keycodes...
  456.  
  457.         PHYSFSX_gets_line_t<200> line_buffer;
  458.         while (PHYSFSX_fgets(line_buffer, infile))
  459.         {
  460.                 if (!line_buffer[0])
  461.                         continue;
  462.                 PHYSFSX_gets_line_t<100> text;
  463.                 sscanf(line_buffer, " %99s %99s ", text.next().data(), buffer.next().data());
  464.                 keycode = DecodeKeyText(text);
  465.                 functionnumber = func_get_index(buffer);
  466.                 if (functionnumber==-1)
  467.                 {
  468.                         UserError( "Unknown function, %s, in %s\n", static_cast<const char *>(buffer), filename );
  469.                 } else if (keycode==-1)
  470.                 {
  471.                         UserError( "Unknown keystroke, %s, in %s\n", static_cast<const char *>(text), filename );
  472.                         //ui_messagebox( -2, -2, 1, buffer, "Ok" );
  473.  
  474.                 } else {
  475.                         kpn.keycode[kpn.numkeys] = keycode;
  476.                         kpn.function_number[kpn.numkeys] = functionnumber;
  477.                         kpn.numkeys++;
  478.                 }
  479.         }
  480.  
  481.         return 1;
  482. }
  483.  
  484. }
  485.