]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Make crosshair picker code similar to the charmap's in order to simplify cell highlig...
authorterencehill <piuntn@gmail.com>
Fri, 1 May 2015 21:08:10 +0000 (23:08 +0200)
committerterencehill <piuntn@gmail.com>
Fri, 1 May 2015 21:26:05 +0000 (23:26 +0200)
gfx/menu/luminos/skinvalues.txt
gfx/menu/wickedx/skinvalues.txt
gfx/menu/xaw/skinvalues.txt
qcsrc/menu/classes.qc
qcsrc/menu/skin-customizables.inc
qcsrc/menu/xonotic/crosshairbutton.qc [deleted file]
qcsrc/menu/xonotic/crosshairpicker.qc [new file with mode: 0644]
qcsrc/menu/xonotic/crosshairpreview.qc [new file with mode: 0644]
qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc

index dd653973c6d74725f2632fc2d380aa20df516092..cce525534d5fabc61ada2b8052fcb5377c257866 100755 (executable)
@@ -173,9 +173,6 @@ COLOR_CHECKBOX_C                '1 1 1'
 COLOR_CHECKBOX_F                '1 1 1'
 COLOR_CHECKBOX_D                '1 1 1'
 
 COLOR_CHECKBOX_F                '1 1 1'
 COLOR_CHECKBOX_D                '1 1 1'
 
-// item: crosshair button
-//   uses "crosshairbutton" images
-
 // dialog background colors
 //   uses "border" images
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
 // dialog background colors
 //   uses "border" images
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
index 7f1ed450027a9dee5142db65088eb3f3f2ebca69..6eecd78cc0ac6272fdae99d952ddc42b4a453295 100644 (file)
@@ -173,9 +173,6 @@ COLOR_CHECKBOX_C                '0.5 0.75 1'
 COLOR_CHECKBOX_F                '0.5 0.75 1'
 COLOR_CHECKBOX_D                '1 1 1'
 
 COLOR_CHECKBOX_F                '0.5 0.75 1'
 COLOR_CHECKBOX_D                '1 1 1'
 
-// item: crosshair button
-//   uses "crosshairbutton" images
-
 // dialog background colors
 //   uses "border" images
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
 // dialog background colors
 //   uses "border" images
 COLOR_DIALOG_MULTIPLAYER        '1 1 1'
index 6de99761e73fbc8305696129ff468c6107ae4c83..bb6b78d16bd67dc80c10d8083e62fcda43623967 100644 (file)
@@ -107,9 +107,6 @@ ALPHA_CREDITS_PERSON            1
 ROWS_CREDITS                    20
 WIDTH_CREDITS                   0.5
 
 ROWS_CREDITS                    20
 WIDTH_CREDITS                   0.5
 
-// item: crosshair button
-//   uses "crosshairbutton" images
-
 // item: cvar list
 ALPHA_CVARLIST_SAVED            1
 ALPHA_CVARLIST_TEMPORARY        0.7
 // item: cvar list
 ALPHA_CVARLIST_SAVED            1
 ALPHA_CVARLIST_TEMPORARY        0.7
index 9b4bb4dab301037d5a46ea809ec69a4a342f2de5..41522d6c5602a65d7b5e419a92fd559c853b1279 100644 (file)
 #include "xonotic/skinlist.qc"
 #include "xonotic/languagelist.qc"
 #include "xonotic/image.qc"
 #include "xonotic/skinlist.qc"
 #include "xonotic/languagelist.qc"
 #include "xonotic/image.qc"
-#include "xonotic/crosshairbutton.qc"
 #include "xonotic/playermodel.qc"
 #include "xonotic/checkbox_slider_invalid.qc"
 #include "xonotic/charmap.qc"
 #include "xonotic/playermodel.qc"
 #include "xonotic/checkbox_slider_invalid.qc"
 #include "xonotic/charmap.qc"
+#include "xonotic/crosshairpicker.qc"
+#include "xonotic/crosshairpreview.qc"
 #include "xonotic/keybinder.qc"
 #include "xonotic/dialog_settings_input.qc"
 #include "xonotic/dialog_settings_input_userbind.qc"
 #include "xonotic/keybinder.qc"
 #include "xonotic/dialog_settings_input.qc"
 #include "xonotic/dialog_settings_input_userbind.qc"
index fa5a5df1998e18f312afc4bae5af75c2c4c04c23..58884a0f99f60eca58b0b917356726b60318428e 100644 (file)
@@ -144,9 +144,6 @@ SKINBEGIN
        SKINFLOAT(ROWS_CREDITS, 20);
        SKINFLOAT(WIDTH_CREDITS, 0.5);
 
        SKINFLOAT(ROWS_CREDITS, 20);
        SKINFLOAT(WIDTH_CREDITS, 0.5);
 
-       // item: crosshair button
-       SKINSTRING(GFX_CROSSHAIRBUTTON, "crosshairbutton");
-
        // item: cvar list
        SKINFLOAT(ALPHA_CVARLIST_SAVED, 1);
        SKINFLOAT(ALPHA_CVARLIST_TEMPORARY, 0.7);
        // item: cvar list
        SKINFLOAT(ALPHA_CVARLIST_SAVED, 1);
        SKINFLOAT(ALPHA_CVARLIST_TEMPORARY, 0.7);
diff --git a/qcsrc/menu/xonotic/crosshairbutton.qc b/qcsrc/menu/xonotic/crosshairbutton.qc
deleted file mode 100644 (file)
index 3b562cb..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifdef INTERFACE
-CLASS(XonoticCrosshairButton) EXTENDS(RadioButton)
-       METHOD(XonoticCrosshairButton, configureXonoticCrosshairButton, void(entity, float, float))
-       METHOD(XonoticCrosshairButton, setChecked, void(entity, float))
-       METHOD(XonoticCrosshairButton, draw, void(entity))
-       ATTRIB(XonoticCrosshairButton, fontSize, float, SKINFONTSIZE_NORMAL)
-       ATTRIB(XonoticCrosshairButton, image, string, SKINGFX_CROSSHAIRBUTTON)
-
-       ATTRIB(XonoticCrosshairButton, useDownAsChecked, float, 1)
-       ATTRIB(XonoticCrosshairButton, src3, string, string_null)
-       ATTRIB(XonoticCrosshairButton, src4, string, string_null)
-
-       ATTRIB(XonoticCrosshairButton, cvarName, string, string_null)
-       ATTRIB(XonoticCrosshairButton, cvarValueFloat, float, 0)
-       METHOD(XonoticCrosshairButton, loadCvars, void(entity))
-       METHOD(XonoticCrosshairButton, saveCvars, void(entity))
-ENDCLASS(XonoticCrosshairButton)
-entity makeXonoticCrosshairButton(float, float);
-#endif
-
-#ifdef IMPLEMENTATION
-entity makeXonoticCrosshairButton(float theGroup, float theCrosshair)
-{
-       entity me;
-       me = spawnXonoticCrosshairButton();
-       me.configureXonoticCrosshairButton(me, theGroup, theCrosshair);
-       return me;
-}
-void XonoticCrosshairButton_configureXonoticCrosshairButton(entity me, float theGroup, float theCrosshair)
-{
-       me.cvarName = "crosshair";
-       me.cvarValueFloat = theCrosshair;
-       me.loadCvars(me);
-       me.configureRadioButton(me, string_null, me.fontSize, me.image, theGroup, 0);
-       me.srcMulti = 1;
-       if(me.cvarValueFloat == -1)
-               me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
-       else
-               me.src3 = strzone(strcat("/gfx/crosshair", ftos(me.cvarValueFloat)));
-       me.src4 = "/gfx/crosshairdot";
-}
-void XonoticCrosshairButton_setChecked(entity me, float val)
-{
-       if(me.cvarValueFloat != -1) // preview shouldn't work as a button
-       if(val != me.checked)
-       {
-               me.checked = val;
-               me.saveCvars(me);
-       }
-}
-void XonoticCrosshairButton_loadCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       me.checked = (cvar(me.cvarName) == me.cvarValueFloat);
-}
-void XonoticCrosshairButton_saveCvars(entity me)
-{
-       if (!me.cvarName)
-               return;
-
-       if(me.checked)
-               cvar_set(me.cvarName, ftos(me.cvarValueFloat));
-       // TODO on an apply button, read _cl_color and execute the color command for it
-}
-void XonoticCrosshairButton_draw(entity me)
-{
-       vector sz, rgb;
-       float a;
-
-
-       if(me.cvarValueFloat == -1)
-       {
-               rgb = stov(cvar_string("crosshair_color"));
-               a = cvar("crosshair_alpha");
-       }
-       else if(me.checked || me.focused)
-       {
-               a = 1;
-               rgb = '1 1 1';
-       }
-       else
-       {
-               a = me.disabledAlpha;
-               rgb = '1 1 1';
-       }
-
-       if(me.cvarValueFloat == -1) // update the preview if this is the preview button
-       {
-               if(me.src3)
-                       strunzone(me.src3);
-               me.src3 = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
-               me.focused = 1;
-               me.checked = 0;
-       }
-
-       SUPER(XonoticCrosshairButton).draw(me);
-
-       sz = draw_PictureSize(me.src3);
-       sz = globalToBoxSize(sz, me.size);
-       if(me.cvarValueFloat == -1)
-       {
-               sz = sz * cvar("crosshair_size"); // (6 * '1 1 0' + ...) * 0.08 here to make visible size changes happen also at bigger sizes
-               /*
-               if(sz_x > 0.95)
-                       sz = sz * (0.95 / sz_x);
-               if(sz_y > 0.95)
-                       sz = sz * (0.95 / sz_y);
-               */
-       }
-       else // show the crosshair picker at full size
-       {
-               sz = sz * (0.95 / sz.x);
-               if(sz.y > 0.95)
-                       sz = sz * (0.95 / sz.y);
-       }
-
-       draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src3, sz, rgb, a);
-       if(cvar("crosshair_dot"))
-       {
-               if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
-                       rgb = stov(cvar_string("crosshair_dot_color"));
-
-               draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src4, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha"));
-       }
-}
-#endif
diff --git a/qcsrc/menu/xonotic/crosshairpicker.qc b/qcsrc/menu/xonotic/crosshairpicker.qc
new file mode 100644 (file)
index 0000000..9236e61
--- /dev/null
@@ -0,0 +1,225 @@
+#ifdef INTERFACE
+CLASS(XonoticCrosshairPicker) EXTENDS(Item)
+       METHOD(XonoticCrosshairPicker, configureXonoticCrosshairPicker, void(entity))
+       METHOD(XonoticCrosshairPicker, mousePress, float(entity, vector))
+       METHOD(XonoticCrosshairPicker, mouseRelease, float(entity, vector))
+       METHOD(XonoticCrosshairPicker, mouseMove, float(entity, vector))
+       METHOD(XonoticCrosshairPicker, mouseDrag, float(entity, vector))
+       METHOD(XonoticCrosshairPicker, keyDown, float(entity, float, float, float))
+       METHOD(XonoticCrosshairPicker, draw, void(entity))
+       ATTRIB(XonoticCrosshairPicker, focusable, float, 1)
+       ATTRIB(XonoticCrosshairPicker, disabled, float, 0)
+       ATTRIB(XonoticCrosshairPicker, alpha, float, 1)
+       ATTRIB(XonoticCrosshairPicker, disabledAlpha, float, SKINALPHA_DISABLED)
+
+       METHOD(XonoticCrosshairPicker, moveFocus, void(entity, vector, vector))
+       METHOD(XonoticCrosshairPicker, setCrosshair, void(entity))
+       ATTRIB(XonoticCrosshairPicker, realCellSize, vector, '0 0 0')
+       ATTRIB(XonoticCrosshairPicker, focusedCell, vector, '-1 -1 0')
+       ATTRIB(XonoticCrosshairPicker, focusedCellTime, float, 0)
+       ATTRIB(XonoticCrosshairPicker, pressedCell, vector, '-1 -1 0')
+ENDCLASS(XonoticCrosshairPicker)
+entity makeXonoticCrosshairPicker();
+#endif
+
+#ifdef IMPLEMENTATION
+
+const float CROSSHAIRPICKER_COLS = 12;
+const float CROSSHAIRPICKER_ROWS = 3;
+
+string crosshairpicker_cellToCrosshair(vector cell)
+{
+       float crosshair = 31 + cell.y * CROSSHAIRPICKER_COLS + cell.x;
+
+       if (crosshair >= 31 && crosshair < 31 + CROSSHAIRPICKER_COLS * CROSSHAIRPICKER_ROWS)
+               return ftos(crosshair);
+       else
+               return "";
+}
+
+entity makeXonoticCrosshairPicker()
+{
+       entity me;
+       me = spawnXonoticCrosshairPicker();
+       me.configureXonoticCrosshairPicker(me);
+       return me;
+}
+
+void XonoticCrosshairPicker_configureXonoticCrosshairPicker(entity me)
+{
+       me.realCellSize = eX / CROSSHAIRPICKER_COLS + eY / CROSSHAIRPICKER_ROWS;
+}
+
+float XonoticCrosshairPicker_mouseMove(entity me, vector coords)
+{
+       vector prevFocusedCell = me.focusedCell;
+       me.focusedCell_x = floor(coords.x * CROSSHAIRPICKER_COLS);
+       me.focusedCell_y = floor(coords.y * CROSSHAIRPICKER_ROWS);
+
+       if(me.focusedCell.x < 0 || me.focusedCell.y < 0 ||
+          me.focusedCell.x >= CROSSHAIRPICKER_COLS || me.focusedCell.y >= CROSSHAIRPICKER_ROWS)
+       {
+               me.focusedCell = '-1 -1 0';
+               return 0;
+       }
+
+       if(me.focusedCell != prevFocusedCell)
+               me.focusedCellTime = time;
+
+       return 1;
+}
+
+float XonoticCrosshairPicker_mouseDrag(entity me, vector coords)
+{
+       return me.mouseMove(me, coords);
+}
+
+float XonoticCrosshairPicker_mousePress(entity me, vector coords)
+{
+       me.mouseMove(me, coords);
+
+       if(me.focusedCell.x >= 0)
+       {
+               me.pressed = 1;
+               me.pressedCell = me.focusedCell;
+       }
+
+       return 1;
+}
+
+float XonoticCrosshairPicker_mouseRelease(entity me, vector coords)
+{
+       if(!me.pressed)
+               return 0;
+
+       me.mouseMove(me, coords);
+
+       if(me.focusedCell == me.pressedCell)
+               me.setCrosshair(me);
+
+       me.pressed = 0;
+       return 1;
+}
+
+float XonoticCrosshairPicker_keyDown(entity me, float key, float ascii, float shift)
+{
+       switch(key)
+       {
+               case K_LEFTARROW:
+               case K_KP_LEFTARROW:
+                       me.moveFocus(me, me.focusedCell, '-1 0 0');
+                       return 1;
+               case K_RIGHTARROW:
+               case K_KP_RIGHTARROW:
+                       me.moveFocus(me, me.focusedCell, '1 0 0');
+                       return 1;
+               case K_UPARROW:
+               case K_KP_UPARROW:
+                       me.moveFocus(me, me.focusedCell, '0 -1 0');
+                       return 1;
+               case K_DOWNARROW:
+               case K_KP_DOWNARROW:
+                       me.moveFocus(me, me.focusedCell, '0 1 0');
+                       return 1;
+               case K_HOME:
+               case K_KP_HOME:
+                       me.focusedCell = '0 0 0';
+                       return 1;
+               case K_END:
+               case K_KP_END:
+                       me.focusedCell_x = CROSSHAIRPICKER_COLS - 1;
+                       me.focusedCell_y = CROSSHAIRPICKER_ROWS - 1;
+                       return 1;
+               case K_ENTER:
+               case K_KP_ENTER:
+               case K_INS:
+               case K_KP_INS:
+                       me.setCrosshair(me);
+                       return 1;
+       }
+       return 0;
+}
+
+void XonoticCrosshairPicker_moveFocus(entity me, vector initialCell, vector step)
+{
+       me.focusedCell_x = mod(me.focusedCell.x + step.x + CROSSHAIRPICKER_COLS, CROSSHAIRPICKER_COLS);
+       me.focusedCell_y = mod(me.focusedCell.y + step.y + CROSSHAIRPICKER_ROWS, CROSSHAIRPICKER_ROWS);
+
+       if(me.focusedCell != initialCell) // Recursion break
+               if(crosshairpicker_cellToCrosshair(me.focusedCell) == "")
+                       me.moveFocus(me, initialCell, step);
+}
+
+void XonoticCrosshairPicker_setCrosshair(entity me)
+{
+       cvar_set("crosshair", crosshairpicker_cellToCrosshair(me.focusedCell));
+}
+
+void XonoticCrosshairPicker_draw(entity me)
+{
+       vector sz, rgb;
+       float save;
+
+       me.focusable = !me.disabled;
+
+       save = draw_alpha;
+       if(me.disabled)
+               draw_alpha *= me.disabledAlpha;
+
+       string crosshair;
+       vector cell, cellPos, crosshairPos;
+       cell = '0 0 0';
+       cellPos = '0 0 0';
+       crosshairPos = '0 0 0';
+
+
+       for(cell_y = 0; cell.y < CROSSHAIRPICKER_ROWS; ++cell.y)
+       {
+               crosshairPos_y = cell.y / CROSSHAIRPICKER_ROWS + 0.5 * me.realCellSize.y;
+               for(cell_x = 0; cell.x < CROSSHAIRPICKER_COLS; ++cell.x)
+               {
+                       crosshair = crosshairpicker_cellToCrosshair(cell);
+
+                       if(crosshair == "")
+                               continue;
+
+                       // Draw focused cell
+                       if(cell == me.focusedCell && me.focused)
+                       {
+                               if(!me.pressed || me.focusedCell == me.pressedCell)
+                               {
+                                       cellPos_x = mod(me.focusedCell.x, CROSSHAIRPICKER_COLS) / CROSSHAIRPICKER_COLS;
+                                       cellPos_y = mod(me.focusedCell.y, CROSSHAIRPICKER_ROWS) / CROSSHAIRPICKER_ROWS;
+                                       draw_Fill(cellPos, me.realCellSize, SKINCOLOR_LISTBOX_FOCUSED, getHighlightAlpha(SKINALPHA_LISTBOX_FOCUSED, SKINFADEALPHA_LISTBOX_FOCUSED, me.focusedCellTime));
+                               }
+                       }
+
+                       // Draw crosshair
+                       crosshairPos_x = cell.x / CROSSHAIRPICKER_COLS + 0.5 * me.realCellSize.x;
+                       string cross = strcat("/gfx/crosshair", crosshairpicker_cellToCrosshair(cell));
+                       sz = draw_PictureSize(cross);
+                       sz = globalToBoxSize(sz, me.size);
+
+                       float ar = sz.x / sz.y;
+                       sz.x = me.realCellSize.x;
+                       sz.y = sz.x / ar;
+
+                       sz = sz * 0.95;
+
+                       rgb = '1 1 1';
+                       draw_Picture(crosshairPos - 0.5 * sz, cross, sz, rgb, me.alpha);
+                       if(cvar("crosshair_dot"))
+                       {
+                               if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
+                                       rgb = stov(cvar_string("crosshair_dot_color"));
+
+                               draw_Picture(crosshairPos - 0.5 * sz * cvar("crosshair_dot_size"), "/gfx/crosshairdot", sz * cvar("crosshair_dot_size"), rgb, me.alpha);
+                       }
+               }
+       }
+
+       draw_alpha = save;
+
+       SUPER(XonoticCrosshairPicker).draw(me);
+}
+#endif
diff --git a/qcsrc/menu/xonotic/crosshairpreview.qc b/qcsrc/menu/xonotic/crosshairpreview.qc
new file mode 100644 (file)
index 0000000..b271f4d
--- /dev/null
@@ -0,0 +1,60 @@
+#ifdef INTERFACE
+CLASS(XonoticCrosshairPreview) EXTENDS(Item)
+       METHOD(XonoticCrosshairPreview, configureXonoticCrosshairPreview, void(entity))
+       METHOD(XonoticCrosshairPreview, draw, void(entity))
+       ATTRIB(XonoticCrosshairPreview, src, string, string_null)
+       ATTRIB(XonoticCrosshairPreview, src2, string, string_null)
+       ATTRIB(XonoticCrosshairPreview, disabled, float, 0)
+       ATTRIB(XonoticCrosshairPreview, disabledAlpha, float, SKINALPHA_DISABLED)
+ENDCLASS(XonoticCrosshairPreview)
+entity makeXonoticCrosshairPreview();
+#endif
+
+#ifdef IMPLEMENTATION
+entity makeXonoticCrosshairPreview()
+{
+       entity me;
+       me = spawnXonoticCrosshairPreview();
+       me.configureXonoticCrosshairPreview(me);
+       return me;
+}
+
+void XonoticCrosshairPreview_configureXonoticCrosshairPreview(entity me)
+{
+       me.src = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+       me.src2 = "/gfx/crosshairdot";
+}
+
+void XonoticCrosshairPreview_draw(entity me)
+{
+       float save;
+       save = draw_alpha;
+       if(me.disabled)
+               draw_alpha *= me.disabledAlpha;
+
+       vector sz, rgb;
+       float a;
+       rgb = stov(cvar_string("crosshair_color"));
+       a = cvar("crosshair_alpha");
+       if(me.src)
+               strunzone(me.src);
+       me.src = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+
+       sz = draw_PictureSize(me.src);
+       sz = globalToBoxSize(sz, me.size);
+       sz = sz * cvar("crosshair_size");
+
+       draw_Picture('0.5 0.5 0' - 0.5 * sz, me.src, sz, rgb, a);
+       if(cvar("crosshair_dot"))
+       {
+               if(cvar("crosshair_dot_color_custom") && (cvar_string("crosshair_dot_color") != "0"))
+                       rgb = stov(cvar_string("crosshair_dot_color"));
+
+               draw_Picture('0.5 0.5 0' - 0.5 * sz * cvar("crosshair_dot_size"), me.src2, sz * cvar("crosshair_dot_size"), rgb, a * cvar("crosshair_dot_alpha"));
+       }
+
+       draw_alpha = save;
+
+       SUPER(XonoticCrosshairPreview).draw(me);
+}
+#endif
index 28cf3708f3af0833b98028ef9b42e433a934292c..3bfcb0bb09ec6571c3df568995c05a8deeec4a33 100644 (file)
@@ -27,7 +27,6 @@ entity makeXonoticGameCrosshairSettingsTab()
 void XonoticGameCrosshairSettingsTab_fill(entity me)
 {
        entity e;
 void XonoticGameCrosshairSettingsTab_fill(entity me)
 {
        entity e;
-       float i;
 
        // crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
        // FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
 
        // crosshair_enabled: 0 = no crosshair options, 1 = no crosshair selection, but everything else enabled, 2 = all crosshair options enabled
        // FIXME: In the future, perhaps make one global crosshair_type cvar which has 0 for disabled, 1 for custom, 2 for per weapon, etc?
@@ -39,27 +38,12 @@ void XonoticGameCrosshairSettingsTab_fill(entity me)
        //me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
        me.TR(me);
        //me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticRadioButton(3, "crosshair_enabled", "2", _("Custom")));
        me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 31; i <= 42; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
-               // show a larger preview of the selected crosshair
-               me.TDempty(me, 0.1);
-               me.TDNoMargin(me, 3, 0.8, e = makeXonoticCrosshairButton(7, -1), '1 1 0'); // crosshair -1 makes this a preview
+               me.TD(me, 3, 2, e = makeXonoticCrosshairPicker());
+                       setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
+               me.TD(me, 3, 1, e = makeXonoticCrosshairPreview());
                        setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
        me.TR(me);
                        setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
        me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 43; i <= 54; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
        me.TR(me);
        me.TR(me);
-               me.TDempty(me, 0.1);
-               for(i = 55; i <= 66; ++i) {
-                       me.TDNoMargin(me, 1, 2 / 12, e = makeXonoticCrosshairButton(4, i), '1 1 0');
-                               setDependentAND(e, "crosshair_per_weapon", 0, 0, "crosshair_enabled", 1, 2);
-               }
        me.TR(me);
                me.TDempty(me, 0.1);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));
        me.TR(me);
                me.TDempty(me, 0.1);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Crosshair size:")));