mirror of
https://github.com/google/pebble.git
synced 2025-05-24 20:24:53 +00:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
164
src/fw/applib/ui/window_stack_animation_round.c
Normal file
164
src/fw/applib/ui/window_stack_animation_round.c
Normal file
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
* Copyright 2024 Google LLC
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "window_stack_animation_round.h"
|
||||
|
||||
#include "animation_timing.h"
|
||||
#include "window_private.h"
|
||||
#include "window_stack.h"
|
||||
|
||||
#include "applib/applib_malloc.auto.h"
|
||||
#include "applib/graphics/graphics.h"
|
||||
#include "applib/graphics/graphics_private.h"
|
||||
#include "applib/graphics/graphics_private_raw.h"
|
||||
#include "applib/graphics/gtypes.h"
|
||||
#include "board/display.h"
|
||||
#include "kernel/ui/kernel_ui.h"
|
||||
#include "services/common/compositor/compositor_transitions.h"
|
||||
#include "system/passert.h"
|
||||
#include "util/attributes.h"
|
||||
#include "util/math.h"
|
||||
#include "util/trig.h"
|
||||
|
||||
// Window transition implementations
|
||||
//////////////////////////////////////
|
||||
|
||||
static uint16_t prv_window_distance_from_screen_bounds(const Window *window) {
|
||||
const GPoint origin = window->layer.frame.origin;
|
||||
return MAX(distance_to_mod_boundary(origin.x, DISP_COLS),
|
||||
distance_to_mod_boundary(origin.y, DISP_ROWS));
|
||||
}
|
||||
|
||||
static void prv_window_transition_render(WindowTransitioningContext *context, GContext *ctx) {
|
||||
const WindowTransitionRoundImplementation *implementation =
|
||||
(WindowTransitionRoundImplementation *)context->implementation;
|
||||
Window *window_to = context->window_to;
|
||||
if (window_to) {
|
||||
// move framebuffer by amount of pixels the window_to moves
|
||||
// => gives impression of a moving window_from
|
||||
const int16_t new_x = window_to->layer.frame.origin.x;
|
||||
const int16_t delta_x = new_x - context->window_to_last_x;
|
||||
graphics_private_move_pixels_horizontally(&ctx->dest_bitmap, delta_x,
|
||||
false /* patch_garbage */);
|
||||
context->window_to_last_x = new_x;
|
||||
|
||||
// render window_from
|
||||
window_render(window_to, ctx);
|
||||
|
||||
// cover whole movement with a ring that distracts from the simple movement
|
||||
uint16_t gap_to_cover = prv_window_distance_from_screen_bounds(window_to);
|
||||
compositor_port_hole_transition_draw_outer_ring(ctx, gap_to_cover, GColorBlack);
|
||||
}
|
||||
}
|
||||
|
||||
static void prv_window_transition_animation_setup(Animation *animation) {
|
||||
WindowTransitioningContext *context = animation_get_context(animation);
|
||||
window_transition_context_appearance_call_all(context);
|
||||
|
||||
const AnimationImplementation *impl = animation_get_implementation(animation);
|
||||
if (impl && impl->update) {
|
||||
// make sure window_to is at its starting position for the transition
|
||||
impl->update(animation, 0);
|
||||
}
|
||||
if (context->window_to) {
|
||||
// store starting position of window_to to know which pixels to update
|
||||
context->window_to_last_x = context->window_to->layer.frame.origin.x;
|
||||
}
|
||||
}
|
||||
|
||||
static GPoint prv_displacement_from(CompositorTransitionDirection direction) {
|
||||
switch (direction) {
|
||||
case CompositorTransitionDirectionUp:
|
||||
return GPoint(0, 1);
|
||||
case CompositorTransitionDirectionDown:
|
||||
return GPoint(0, -1);
|
||||
case CompositorTransitionDirectionLeft:
|
||||
return GPoint(1, 0);
|
||||
case CompositorTransitionDirectionRight:
|
||||
return GPoint(-1, 0);
|
||||
case CompositorTransitionDirectionNone:
|
||||
default:
|
||||
return GPointZero;
|
||||
}
|
||||
}
|
||||
|
||||
static CompositorTransitionDirection prv_direction_from_context(
|
||||
const WindowTransitioningContext *context) {
|
||||
return ((WindowTransitionRoundImplementation *)context->implementation)->transition_direction;
|
||||
}
|
||||
|
||||
static void prv_window_transition_animation_update(Animation *animation,
|
||||
const AnimationProgress progress) {
|
||||
const WindowTransitioningContext *context = animation_get_context(animation);
|
||||
const CompositorTransitionDirection direction = prv_direction_from_context(context);
|
||||
Window *window_to = context->window_to;
|
||||
if (window_to) {
|
||||
const GPoint factor = prv_displacement_from(direction);
|
||||
|
||||
// in the video for S4 with 180px I measured 80px
|
||||
// this expression tries express this in a future-proof manner in case we will have round
|
||||
// displays with a different resolution
|
||||
const int16_t offset_value = DISP_COLS * 80 / 180;
|
||||
const GPoint offset = GPoint(factor.x * offset_value, factor.y * offset_value);
|
||||
|
||||
const AnimationProgress half_time = ANIMATION_NORMALIZED_MAX / 2;
|
||||
const bool first_half = progress < half_time;
|
||||
GPoint from;
|
||||
GPoint to;
|
||||
|
||||
// does a movement of the first pixels, a cut, and then a movement of the last pixels
|
||||
if (first_half) {
|
||||
from = GPoint(factor.x * DISP_COLS, factor.y * DISP_ROWS);
|
||||
to = gpoint_sub(from, offset);
|
||||
} else {
|
||||
to = GPointZero;
|
||||
from = gpoint_add(to, offset);
|
||||
}
|
||||
window_to->layer.frame.origin = interpolate_gpoint(progress, from, to);
|
||||
window_schedule_render(window_to);
|
||||
}
|
||||
}
|
||||
|
||||
static Animation *prv_window_transition_create_animation(WindowTransitioningContext *context) {
|
||||
static AnimationImplementation const impl = {
|
||||
.setup = prv_window_transition_animation_setup,
|
||||
.update = prv_window_transition_animation_update,
|
||||
};
|
||||
|
||||
Animation *animation = animation_create();
|
||||
animation_set_implementation(animation, &impl);
|
||||
animation_set_handlers(animation, (AnimationHandlers){}, context);
|
||||
animation_set_curve(animation, AnimationCurveEaseInOut);
|
||||
animation_set_duration(animation, PORT_HOLE_TRANSITION_DURATION_MS);
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
const WindowTransitionRoundImplementation g_window_transition_default_push_implementation_round = {
|
||||
.implementation = {
|
||||
.create_animation = prv_window_transition_create_animation,
|
||||
.render = prv_window_transition_render,
|
||||
},
|
||||
.transition_direction = CompositorTransitionDirectionLeft,
|
||||
};
|
||||
|
||||
const WindowTransitionRoundImplementation g_window_transition_default_pop_implementation_round = {
|
||||
.implementation = {
|
||||
.create_animation = prv_window_transition_create_animation,
|
||||
.render = prv_window_transition_render,
|
||||
},
|
||||
.transition_direction = CompositorTransitionDirectionRight,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue