diff --git a/Marlin/src/lcd/tft/touch.cpp b/Marlin/src/lcd/tft/touch.cpp index 62619d90b3..0815f3d7fd 100644 --- a/Marlin/src/lcd/tft/touch.cpp +++ b/Marlin/src/lcd/tft/touch.cpp @@ -82,87 +82,92 @@ void Touch::idle() { if (now == next_touch_ms) return; next_touch_ms = now; - // Get the point and if the screen is touched do more + // Get the point where the screen is touched int16_t _x, _y; - if (get_point(&_x, &_y)) { + const bool is_touched = get_point(&_x, &_y); - #if HAS_RESUME_CONTINUE - // UI is waiting for a click anywhere? - if (marlin.wait_for_user) { - touch_control_type = CLICK; - ui.lcd_clicked = true; - if (ui.external_control) marlin.user_resume(); - return; - } - #endif - - ui.reset_status_timeout(now); - - // If nada_start_ms is set the touch is being held down outside of a control. - // With TOUCH_SCREEN_CALIBRATION a long hold (2.5s by default) opens to the calibration screen. - // As long as this non-action touch is still held down, return. - if (nada_start_ms) { - #if ENABLED(TOUCH_SCREEN_CALIBRATION) - if (touch_control_type == NONE && ELAPSED(now, nada_start_ms, TOUCH_SCREEN_HOLD_TO_CALIBRATE_MS) && ui.on_status_screen()) - ui.goto_screen(touch_screen_calibration); - #endif - return; - } - - // First time touched, ignore the control for a tiny interval as a debounce - if (time_to_hold == 0) time_to_hold = now + MINIMUM_HOLD_TIME; - - // For a held control ignore the continuing touch until time elapses - // to prevent spamming controls. - if (PENDING(now, time_to_hold)) return; - - // Was a previous point recorded? Then we are dragging, maybe in a control. - if (x != 0 && y != 0) { - // If a control was set by hold() keep sliding it until its bounds are exited - if (current_control) { - if (WITHIN(x, current_control->x - FREE_MOVE_RANGE, current_control->x + current_control->width + FREE_MOVE_RANGE) && WITHIN(y, current_control->y - FREE_MOVE_RANGE, current_control->y + current_control->height + FREE_MOVE_RANGE)) { - LIMIT(x, current_control->x, current_control->x + current_control->width); - LIMIT(y, current_control->y, current_control->y + current_control->height); - touch(current_control); - } - else - current_control = nullptr; - } - else { - // Initiate a touch on the first control containing the touch position - // If this is a button the touch initiates the action on the button. - // TODO: Apply standard UI practice for Tap events: - // - Take a short press-and-release as a Tap. - // - If more taps occur before "tap detect time" elapses, increment taps counter. - // - When "tap detect time" elapses activate the button, sending the number of taps. - for (uint16_t i = 0; i < controls_count; ++i) { - auto &c = controls[i]; - if ((WITHIN(x, c.x, c.x + c.width) && WITHIN(y, c.y, c.y + c.height)) || TERN0(TOUCH_SCREEN_CALIBRATION, c.type == CALIBRATE)) { - touch_control_type = c.type; - touch(&c); - break; - } - } - } - - if (!current_control) - nada_start_ms = now; - } - x = _x; - y = _y; - } - else { - // No touch is occurring. Continually reset these values: + // If no touch is occurring then reset all touch info and exit + if (!is_touched) { x = y = 0; current_control = nullptr; nada_start_ms = 0; touch_control_type = NONE; time_to_hold = 0; - repeat_delay = TOUCH_REPEAT_DELAY; + repeat_delay = MINIMUM_HOLD_TIME; + return; } + + // A new touch or a drag... + + #if HAS_RESUME_CONTINUE + // UI is waiting for a click anywhere? + if (marlin.wait_for_user) { + touch_control_type = CLICK; + ui.lcd_clicked = true; + if (ui.external_control) marlin.user_resume(); + return; + } + #endif + + ui.reset_status_timeout(now); + + // If nada_start_ms is set, a touch outside of controls is being held down. + // With TOUCH_SCREEN_CALIBRATION a long hold (2.5s by default) opens to the calibration screen. + // As long as this non-action touch is still held down, return. + if (nada_start_ms) { + #if ENABLED(TOUCH_SCREEN_CALIBRATION) + if (touch_control_type == NONE && ELAPSED(now, nada_start_ms, TOUCH_SCREEN_HOLD_TO_CALIBRATE_MS) && ui.on_status_screen()) + ui.goto_screen(touch_screen_calibration); + #endif + return; + } + + // First time touched, ignore the control for a tiny interval as a debounce + if (time_to_hold == 0) time_to_hold = now + MINIMUM_HOLD_TIME; + + // For a held control ignore the continuing touch until time elapses + // to prevent spamming controls. + // This timestamp will be updated as controls are held down. + if (PENDING(now, time_to_hold)) return; + + // Was a previous point recorded? Then we are dragging, maybe in a control. + if (x != 0 && y != 0) { + // If a control was set by hold() keep sliding it until its bounds are exited + if (current_control) { + if (WITHIN(x, current_control->x - FREE_MOVE_RANGE, current_control->x + current_control->width + FREE_MOVE_RANGE) && WITHIN(y, current_control->y - FREE_MOVE_RANGE, current_control->y + current_control->height + FREE_MOVE_RANGE)) { + LIMIT(x, current_control->x, current_control->x + current_control->width); + LIMIT(y, current_control->y, current_control->y + current_control->height); + touch(current_control); + } + else + current_control = nullptr; + } + else { + // Initiate a touch on the first control containing the touch position. + // If this is a button the touch initiates the action on the button. + // TODO: Apply standard UI practice for Tap events: + // - Take a short press-and-release as a Tap. + // - If more taps occur before "tap detect time" elapses, increment taps counter. + // - When "tap detect time" elapses activate the button, sending the number of taps. + for (uint16_t i = 0; i < controls_count; ++i) { + auto &c = controls[i]; + if ((WITHIN(x, c.x, c.x + c.width) && WITHIN(y, c.y, c.y + c.height)) || TERN0(TOUCH_SCREEN_CALIBRATION, c.type == CALIBRATE)) { + touch_control_type = c.type; + touch(&c); + break; + } + } + } + + if (!current_control) nada_start_ms = now; + } + + // Update previous point in continuing touch or drag + x = _x; + y = _y; } -// Handle a touch first detected in a control +// Handle a touch, repeat-touch, or drag in a control void Touch::touch(touch_control_t * const control) { switch (control->type) { @@ -217,11 +222,20 @@ void Touch::touch(touch_control_t * const control) { break; // A slider is held until the touch ends, no repeat delay - case SLIDER: hold(control); ui.encoderPosition = (x - control->x) * control->data / control->width; break; + case SLIDER: + hold(control); + ui.encoderPosition = (x - control->x) * control->data / control->width; + break; - // Increase / Decrease controls are held with a repeat delay - case INCREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); break; - case DECREASE: hold(control, repeat_delay - 5); TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); break; + // Increase / Decrease controls are held with an ever-decreasing repeat delay + case INCREASE: + hold(control, repeat_delay - 5, TOUCH_REPEAT_FIRST_DELAY); + TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff++ : ui.encoderPosition++, ui.encoderPosition++); + break; + case DECREASE: + hold(control, repeat_delay - 5, TOUCH_REPEAT_FIRST_DELAY); + TERN(AUTO_BED_LEVELING_UBL, ui.external_control ? bedlevel.encoder_diff-- : ui.encoderPosition--, ui.encoderPosition--); + break; // Other controls behave like menu items @@ -296,7 +310,10 @@ void Touch::touch(touch_control_t * const control) { break; #if ENABLED(AUTO_BED_LEVELING_UBL) - case UBL: hold(control, UBL_REPEAT_DELAY); ui.encoderPosition += control->data; break; + case UBL: + hold(control, UBL_REPEAT_DELAY, TOUCH_REPEAT_FIRST_DELAY); + ui.encoderPosition += control->data; + break; #endif // TODO: TOUCH could receive data to pass to the callback diff --git a/Marlin/src/lcd/tft/touch.h b/Marlin/src/lcd/tft/touch.h index cf52f896bc..991619e570 100644 --- a/Marlin/src/lcd/tft/touch.h +++ b/Marlin/src/lcd/tft/touch.h @@ -64,12 +64,12 @@ typedef struct __attribute__((__packed__)) { intptr_t data; } touch_control_t; -#define MAX_CONTROLS 16 -#define MINIMUM_HOLD_TIME 15 -#define TOUCH_REPEAT_DELAY 75 -#define MIN_REPEAT_DELAY 25 -#define UBL_REPEAT_DELAY 125 -#define FREE_MOVE_RANGE 32 +#define MAX_CONTROLS 16 +#define MINIMUM_HOLD_TIME 15 // Debounce delay for ignoring short accidental touch +#define TOUCH_REPEAT_DELAY 100 // 1/10s Repeat delay for key-like buttons +#define MIN_REPEAT_DELAY 25 // Smallest permitted repeat delay for controls that speed up the longer they are held +#define UBL_REPEAT_DELAY 125 // Repeat delay for a held control +#define FREE_MOVE_RANGE 32 // Area around a control allowed before aborting a held control #define TSLP_SLEEPING 1