+ }
+
+ BackToFront();
+ DoAnimation();
+
+ /* don't eat all CPU time */
+ Delay(10);
+ }
+
+ /* write new key bindings back to player setup */
+ setup.input[player_nr].key = custom_key;
+
+ StopAnimation();
+ DrawSetupScreen_Input();
+}
+
+static boolean CalibrateJoystickMain(int player_nr)
+{
+ int new_joystick_xleft = JOYSTICK_XMIDDLE;
+ int new_joystick_xright = JOYSTICK_XMIDDLE;
+ int new_joystick_yupper = JOYSTICK_YMIDDLE;
+ int new_joystick_ylower = JOYSTICK_YMIDDLE;
+ int new_joystick_xmiddle, new_joystick_ymiddle;
+
+ int joystick_fd = joystick.fd[player_nr];
+ int x, y, last_x, last_y, xpos = 8, ypos = 3;
+ boolean check[3][3];
+ int check_remaining = 3 * 3;
+ int joy_x, joy_y;
+ int joy_value;
+ int result = -1;
+
+ if (joystick.status == JOYSTICK_NOT_AVAILABLE)
+ return FALSE;
+
+ if (joystick_fd < 0 || !setup.input[player_nr].use_joystick)
+ return FALSE;
+
+ ClearWindow();
+
+ for(y=0; y < 3; y++)
+ {
+ for(x=0; x < 3; x++)
+ {
+ DrawGraphic(xpos + x - 1, ypos + y - 1, IMG_MENU_CALIBRATE_BLUE, 0);
+ check[x][y] = FALSE;
+ }
+ }
+
+ DrawText(mSX, mSY + 6 * 32, " ROTATE JOYSTICK ", FONT_TITLE_1);
+ DrawText(mSX, mSY + 7 * 32, "IN ALL DIRECTIONS", FONT_TITLE_1);
+ DrawText(mSX + 16, mSY + 9 * 32, " IF ALL BALLS ", FONT_TITLE_1);
+ DrawText(mSX, mSY + 10 * 32, " ARE YELLOW, ", FONT_TITLE_1);
+ DrawText(mSX, mSY + 11 * 32, " CENTER JOYSTICK ", FONT_TITLE_1);
+ DrawText(mSX, mSY + 12 * 32, " AND ", FONT_TITLE_1);
+ DrawText(mSX, mSY + 13 * 32, "PRESS ANY BUTTON!", FONT_TITLE_1);
+
+ joy_value = Joystick(player_nr);
+ last_x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
+ last_y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
+
+ /* eventually uncalibrated center position (joystick could be uncentered) */
+ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
+ return FALSE;
+
+ new_joystick_xmiddle = joy_x;
+ new_joystick_ymiddle = joy_y;
+
+ DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_RED, 0);
+ BackToFront();
+
+ while(Joystick(player_nr) & JOY_BUTTON); /* wait for released button */
+ InitAnimation();
+
+ while(result < 0)
+ {
+ if (PendingEvent()) /* got event */
+ {
+ Event event;
+
+ NextEvent(&event);
+
+ switch(event.type)
+ {
+ case EVENT_KEYPRESS:
+ switch(GetEventKey((KeyEvent *)&event, TRUE))
+ {
+ case KSYM_Return:
+ if (check_remaining == 0)
+ result = 1;
+ break;
+
+ case KSYM_Escape:
+ result = 0;
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case EVENT_KEYRELEASE:
+ key_joystick_mapping = 0;
+ break;
+
+ default:
+ HandleOtherEvents(&event);
+ break;
+ }
+ }
+
+ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
+ return FALSE;
+
+ new_joystick_xleft = MIN(new_joystick_xleft, joy_x);
+ new_joystick_xright = MAX(new_joystick_xright, joy_x);
+ new_joystick_yupper = MIN(new_joystick_yupper, joy_y);
+ new_joystick_ylower = MAX(new_joystick_ylower, joy_y);
+
+ setup.input[player_nr].joy.xleft = new_joystick_xleft;
+ setup.input[player_nr].joy.yupper = new_joystick_yupper;
+ setup.input[player_nr].joy.xright = new_joystick_xright;
+ setup.input[player_nr].joy.ylower = new_joystick_ylower;
+ setup.input[player_nr].joy.xmiddle = new_joystick_xmiddle;
+ setup.input[player_nr].joy.ymiddle = new_joystick_ymiddle;
+
+ CheckJoystickData();
+
+ joy_value = Joystick(player_nr);
+
+ if (joy_value & JOY_BUTTON && check_remaining == 0)
+ result = 1;
+
+ x = (joy_value & JOY_LEFT ? -1 : joy_value & JOY_RIGHT ? +1 : 0);
+ y = (joy_value & JOY_UP ? -1 : joy_value & JOY_DOWN ? +1 : 0);
+
+ if (x != last_x || y != last_y)
+ {
+ DrawGraphic(xpos + last_x, ypos + last_y, IMG_MENU_CALIBRATE_YELLOW, 0);
+ DrawGraphic(xpos + x, ypos + y, IMG_MENU_CALIBRATE_RED, 0);
+
+ last_x = x;
+ last_y = y;
+
+ if (check_remaining > 0 && !check[x+1][y+1])
+ {
+ check[x+1][y+1] = TRUE;
+ check_remaining--;
+ }
+
+#if 0
+#ifdef DEBUG
+ printf("LEFT / MIDDLE / RIGHT == %d / %d / %d\n",
+ setup.input[player_nr].joy.xleft,
+ setup.input[player_nr].joy.xmiddle,
+ setup.input[player_nr].joy.xright);
+ printf("UP / MIDDLE / DOWN == %d / %d / %d\n",
+ setup.input[player_nr].joy.yupper,
+ setup.input[player_nr].joy.ymiddle,
+ setup.input[player_nr].joy.ylower);
+#endif
+#endif
+
+ }
+
+ BackToFront();
+ DoAnimation();
+
+ /* don't eat all CPU time */
+ Delay(10);
+ }
+
+ /* calibrated center position (joystick should now be centered) */
+ if (!ReadJoystick(joystick_fd, &joy_x, &joy_y, NULL, NULL))
+ return FALSE;
+
+ new_joystick_xmiddle = joy_x;
+ new_joystick_ymiddle = joy_y;
+
+ StopAnimation();
+
+ DrawSetupScreen_Input();
+
+ /* wait until the last pressed button was released */
+ while (Joystick(player_nr) & JOY_BUTTON)
+ {
+ if (PendingEvent()) /* got event */
+ {
+ Event event;
+
+ NextEvent(&event);
+ HandleOtherEvents(&event);
+
+ Delay(10);
+ }
+ }
+
+ return TRUE;
+}
+
+void CalibrateJoystick(int player_nr)
+{
+ if (!CalibrateJoystickMain(player_nr))
+ {
+ ClearWindow();
+
+ DrawText(mSX + 16, mSY + 6*32, " JOYSTICK NOT ", FONT_TITLE_1);
+ DrawText(mSX, mSY + 7*32, " AVAILABLE ", FONT_TITLE_1);
+ BackToFront();
+ Delay(2000); /* show error message for two seconds */
+ }
+}
+
+void DrawSetupScreen()
+{
+ DeactivateJoystick();
+
+ SetMainBackgroundImage(IMG_BACKGROUND_SETUP);
+
+ if (setup_mode == SETUP_MODE_INPUT)
+ DrawSetupScreen_Input();
+ else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
+ DrawChooseTree(&artwork.gfx_current);
+ else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
+ DrawChooseTree(&artwork.snd_current);
+ else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
+ DrawChooseTree(&artwork.mus_current);
+ else
+ DrawSetupScreen_Generic();
+}
+
+void HandleSetupScreen(int mx, int my, int dx, int dy, int button)
+{
+ if (setup_mode == SETUP_MODE_INPUT)
+ HandleSetupScreen_Input(mx, my, dx, dy, button);
+ else if (setup_mode == SETUP_MODE_CHOOSE_GRAPHICS)
+ HandleChooseTree(mx, my, dx, dy, button, &artwork.gfx_current);
+ else if (setup_mode == SETUP_MODE_CHOOSE_SOUNDS)
+ HandleChooseTree(mx, my, dx, dy, button, &artwork.snd_current);
+ else if (setup_mode == SETUP_MODE_CHOOSE_MUSIC)
+ HandleChooseTree(mx, my, dx, dy, button, &artwork.mus_current);
+ else
+ HandleSetupScreen_Generic(mx, my, dx, dy, button);
+}
+
+void HandleGameActions()
+{
+ if (game_status != GAME_MODE_PLAYING)
+ return;
+
+ if (local_player->LevelSolved)
+ GameWon();
+
+ if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+ TapeStop();
+
+ GameActions();
+
+ BackToFront();
+
+#if 1
+ if (tape.auto_play && !tape.playing)
+ AutoPlayTape(); /* continue automatically playing next tape */
+#endif
+}
+
+/* ---------- new screen button stuff -------------------------------------- */
+
+/* graphic position and size values for buttons and scrollbars */
+#define SC_SCROLLBUTTON_XSIZE 32
+#define SC_SCROLLBUTTON_YSIZE 32
+
+#define SC_SCROLL_UP_XPOS (SXSIZE - SC_SCROLLBUTTON_XSIZE)
+#define SC_SCROLL_UP_YPOS SC_SCROLLBUTTON_YSIZE
+#define SC_SCROLL_DOWN_XPOS SC_SCROLL_UP_XPOS
+#define SC_SCROLL_DOWN_YPOS (SYSIZE - SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_VERTICAL_XPOS SC_SCROLL_UP_XPOS
+#define SC_SCROLL_VERTICAL_YPOS (SC_SCROLL_UP_YPOS + SC_SCROLLBUTTON_YSIZE)
+#define SC_SCROLL_VERTICAL_XSIZE SC_SCROLLBUTTON_XSIZE
+#define SC_SCROLL_VERTICAL_YSIZE (SYSIZE - 3 * SC_SCROLLBUTTON_YSIZE)
+
+#define SC_BORDER_SIZE 14
+
+static struct
+{
+ int gfx_unpressed, gfx_pressed;
+ int x, y;
+ int gadget_id;
+ char *infotext;
+} scrollbutton_info[NUM_SCREEN_SCROLLBUTTONS] =
+{
+ {
+ IMG_MENU_BUTTON_UP, IMG_MENU_BUTTON_UP_ACTIVE,
+ SC_SCROLL_UP_XPOS, SC_SCROLL_UP_YPOS,
+ SCREEN_CTRL_ID_SCROLL_UP,
+ "scroll up"
+ },
+ {
+ IMG_MENU_BUTTON_DOWN, IMG_MENU_BUTTON_DOWN_ACTIVE,
+ SC_SCROLL_DOWN_XPOS, SC_SCROLL_DOWN_YPOS,
+ SCREEN_CTRL_ID_SCROLL_DOWN,
+ "scroll down"
+ }
+};
+
+static struct
+{
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+ Bitmap **gfx_unpressed, **gfx_pressed;
+#else
+ int gfx_unpressed, gfx_pressed;
+#endif
+ int x, y;
+ int width, height;
+ int type;
+ int gadget_id;
+ char *infotext;
+} scrollbar_info[NUM_SCREEN_SCROLLBARS] =
+{
+ {
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+ &scrollbar_bitmap[0], &scrollbar_bitmap[1],
+#else
+ IMG_MENU_SCROLLBAR, IMG_MENU_SCROLLBAR_ACTIVE,
+#endif
+ SX + SC_SCROLL_VERTICAL_XPOS, SY + SC_SCROLL_VERTICAL_YPOS,
+ SC_SCROLL_VERTICAL_XSIZE, SC_SCROLL_VERTICAL_YSIZE,
+ GD_TYPE_SCROLLBAR_VERTICAL,
+ SCREEN_CTRL_ID_SCROLL_VERTICAL,
+ "scroll level series vertically"
+ }
+};
+
+static void CreateScreenScrollbuttons()
+{
+ struct GadgetInfo *gi;
+ unsigned long event_mask;
+ int i;
+
+ for (i=0; i<NUM_SCREEN_SCROLLBUTTONS; i++)
+ {
+ Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
+ int gfx_unpressed, gfx_pressed;
+ int x, y, width, height;
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+ int id = scrollbutton_info[i].gadget_id;
+
+ x = scrollbutton_info[i].x;
+ y = scrollbutton_info[i].y;
+
+ event_mask = GD_EVENT_PRESSED | GD_EVENT_REPEATED;
+
+ x += SX;
+ y += SY;
+ width = SC_SCROLLBUTTON_XSIZE;
+ height = SC_SCROLLBUTTON_YSIZE;
+
+ gfx_unpressed = scrollbutton_info[i].gfx_unpressed;
+ gfx_pressed = scrollbutton_info[i].gfx_pressed;
+ gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
+ gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
+ gd_x1 = graphic_info[gfx_unpressed].src_x;
+ gd_y1 = graphic_info[gfx_unpressed].src_y;
+ gd_x2 = graphic_info[gfx_pressed].src_x;
+ gd_y2 = graphic_info[gfx_pressed].src_y;
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, scrollbutton_info[i].infotext,
+ GDI_X, x,
+ GDI_Y, y,
+ GDI_WIDTH, width,
+ GDI_HEIGHT, height,
+ GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
+ GDI_STATE, GD_BUTTON_UNPRESSED,
+ GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_ACTION, HandleScreenGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ screen_gadget[id] = gi;
+ }
+}
+
+static void CreateScreenScrollbars()
+{
+ int i;
+
+ for (i=0; i<NUM_SCREEN_SCROLLBARS; i++)
+ {
+ Bitmap *gd_bitmap_unpressed, *gd_bitmap_pressed;
+#if !defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+ int gfx_unpressed, gfx_pressed;
+#endif
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+ struct GadgetInfo *gi;
+ int items_max, items_visible, item_position;
+ unsigned long event_mask;
+ int num_page_entries = MAX_MENU_ENTRIES_ON_SCREEN - 1;
+ int id = scrollbar_info[i].gadget_id;
+
+ items_max = num_page_entries;
+ items_visible = num_page_entries;
+ item_position = 0;
+
+ event_mask = GD_EVENT_MOVING | GD_EVENT_OFF_BORDERS;
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+ gd_bitmap_unpressed = *scrollbar_info[i].gfx_unpressed;
+ gd_bitmap_pressed = *scrollbar_info[i].gfx_pressed;
+ gd_x1 = 0;
+ gd_y1 = 0;
+ gd_x2 = 0;
+ gd_y2 = 0;
+#else
+ gfx_unpressed = scrollbar_info[i].gfx_unpressed;
+ gfx_pressed = scrollbar_info[i].gfx_pressed;
+ gd_bitmap_unpressed = graphic_info[gfx_unpressed].bitmap;
+ gd_bitmap_pressed = graphic_info[gfx_pressed].bitmap;
+ gd_x1 = graphic_info[gfx_unpressed].src_x;
+ gd_y1 = graphic_info[gfx_unpressed].src_y;
+ gd_x2 = graphic_info[gfx_pressed].src_x;
+ gd_y2 = graphic_info[gfx_pressed].src_y;
+#endif
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_CUSTOM_TYPE_ID, i,
+ GDI_INFO_TEXT, scrollbar_info[i].infotext,
+ GDI_X, scrollbar_info[i].x,
+ GDI_Y, scrollbar_info[i].y,
+ GDI_WIDTH, scrollbar_info[i].width,
+ GDI_HEIGHT, scrollbar_info[i].height,
+ GDI_TYPE, scrollbar_info[i].type,
+ GDI_SCROLLBAR_ITEMS_MAX, items_max,
+ GDI_SCROLLBAR_ITEMS_VISIBLE, items_visible,
+ GDI_SCROLLBAR_ITEM_POSITION, item_position,
+ GDI_STATE, GD_BUTTON_UNPRESSED,
+ GDI_DESIGN_UNPRESSED, gd_bitmap_unpressed, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_bitmap_pressed, gd_x2, gd_y2,
+ GDI_BORDER_SIZE, SC_BORDER_SIZE, SC_BORDER_SIZE,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_ACTION, HandleScreenGadgets,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ screen_gadget[id] = gi;
+ }
+}
+
+void CreateScreenGadgets()
+{
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+ int i;
+
+ for (i=0; i < NUM_SCROLLBAR_BITMAPS; i++)
+ {
+ scrollbar_bitmap[i] = CreateBitmap(TILEX, TILEY, DEFAULT_DEPTH);
+
+ /* copy pointers to clip mask and GC */
+ scrollbar_bitmap[i]->clip_mask =
+ graphic_info[IMG_MENU_SCROLLBAR + i].clip_mask;
+ scrollbar_bitmap[i]->stored_clip_gc =
+ graphic_info[IMG_MENU_SCROLLBAR + i].clip_gc;
+
+ BlitBitmap(graphic_info[IMG_MENU_SCROLLBAR + i].bitmap,
+ scrollbar_bitmap[i],
+ graphic_info[IMG_MENU_SCROLLBAR + i].src_x,
+ graphic_info[IMG_MENU_SCROLLBAR + i].src_y,
+ TILEX, TILEY, 0, 0);
+ }
+#endif
+
+ CreateScreenScrollbuttons();
+ CreateScreenScrollbars();
+}
+
+void FreeScreenGadgets()
+{
+ int i;
+
+#if defined(TARGET_X11_NATIVE_PERFORMANCE_WORKAROUND)
+ for (i=0; i < NUM_SCROLLBAR_BITMAPS; i++)
+ {
+ /* prevent freeing clip mask and GC twice */
+ scrollbar_bitmap[i]->clip_mask = None;
+ scrollbar_bitmap[i]->stored_clip_gc = None;
+
+ FreeBitmap(scrollbar_bitmap[i]);
+ }
+#endif
+
+ for (i=0; i<NUM_SCREEN_GADGETS; i++)
+ FreeGadget(screen_gadget[i]);
+}
+
+void MapChooseTreeGadgets(TreeInfo *ti)
+{
+ int num_entries = numTreeInfoInGroup(ti);
+ int i;
+
+ if (num_entries <= MAX_MENU_ENTRIES_ON_SCREEN)
+ return;
+
+ for (i=0; i<NUM_SCREEN_GADGETS; i++)
+ MapGadget(screen_gadget[i]);
+}
+
+void UnmapChooseTreeGadgets()
+{
+ int i;
+
+ for (i=0; i<NUM_SCREEN_GADGETS; i++)
+ UnmapGadget(screen_gadget[i]);
+}
+
+static void HandleScreenGadgets(struct GadgetInfo *gi)
+{
+ int id = gi->custom_id;
+
+ if (game_status != GAME_MODE_LEVELS && game_status != GAME_MODE_SETUP)
+ return;
+
+ switch (id)
+ {
+ case SCREEN_CTRL_ID_SCROLL_UP:
+ if (game_status == GAME_MODE_LEVELS)
+ HandleChooseLevel(mSX,mSY + 32, 0,0, MB_MENU_MARK);
+ else if (game_status == GAME_MODE_SETUP)
+ HandleSetupScreen(mSX,mSY + 32, 0,0, MB_MENU_MARK);