Blender V5.0
time_scrub_ui.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2019 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_context.hh"
10#include "BKE_scene.hh"
11
12#include "GPU_immediate.hh"
13#include "GPU_matrix.hh"
14#include "GPU_state.hh"
15
16#include "ED_time_scrub_ui.hh"
17
18#include "WM_api.hh"
19#include "WM_types.hh"
20
21#include "UI_interface.hh"
22#include "UI_interface_icons.hh"
24#include "UI_resources.hh"
25#include "UI_view2d.hh"
26
27#include "DNA_scene_types.h"
28
29#include "BLI_math_base.h"
30#include "BLI_rect.h"
31#include "BLI_string_utf8.h"
32#include "BLI_timecode.h"
33
34#include "RNA_access.hh"
35#include "RNA_prototypes.hh"
36
37void ED_time_scrub_region_rect_get(const ARegion *region, rcti *r_rect)
38{
39 r_rect->xmin = 0;
40 r_rect->xmax = region->winx;
41 r_rect->ymax = region->winy;
42 r_rect->ymin = r_rect->ymax - UI_TIME_SCRUB_MARGIN_Y;
43}
44
45static int get_centered_text_y(const rcti *rect)
46{
47 return BLI_rcti_cent_y(rect) - UI_SCALE_FAC * 4;
48}
49
50static void draw_background(const rcti *rect)
51{
53 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
55
57
59
60 immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
61
63
65}
66
68 const Scene *scene, bool display_seconds, int frame, char *r_str, uint str_maxncpy)
69{
70 if (display_seconds) {
72 r_str, str_maxncpy, -1, FRA2TIME(frame), scene->frames_per_second(), U.timecode_style);
73 }
74 else {
75 BLI_snprintf_utf8(r_str, str_maxncpy, "%d", frame);
76 }
77}
78
79static void draw_current_frame(const Scene *scene,
80 bool display_seconds,
81 const View2D *v2d,
82 const rcti *scrub_region_rect,
83 int current_frame,
84 bool display_stalk = true)
85{
86 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
87 const int frame_x = UI_view2d_view_to_region_x(v2d, current_frame);
88 const float subframe_x = UI_view2d_view_to_region_x(v2d, BKE_scene_ctime_get(scene));
89 char frame_str[64];
90 get_current_time_str(scene, display_seconds, current_frame, frame_str, sizeof(frame_str));
91 const float text_width = UI_fontstyle_string_width(fstyle, frame_str);
92 const float text_padding = 4.0f * UI_SCALE_FAC;
93 const float box_min_width = 24.0f * UI_SCALE_FAC;
94 const float box_width = std::max(text_width + (2.0f * text_padding), box_min_width);
95 const float box_margin = 2.0f * UI_SCALE_FAC;
96 float shadow_width = UI_SCALE_FAC;
97 const float tri_top = ceil(scrub_region_rect->ymin + box_margin);
98 const float tri_half_width = 6.0f * UI_SCALE_FAC;
99 const float tri_height = 6.0f * UI_SCALE_FAC;
100 rctf rect{};
101 uint pos;
102
103 float fg_color[4];
105 float bg_color[4];
106 UI_GetThemeColorShade4fv(TH_BACK, -20, bg_color);
107
108 if (display_stalk) {
109 /* Shadow for triangle below frame box. */
111 pos = GPU_vertformat_attr_add(format, "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
114 GPU_polygon_smooth(true);
115 immUniformColor4fv(bg_color);
117 const float diag_offset = 0.4f * UI_SCALE_FAC;
118 immVertex2f(pos, floor(frame_x - tri_half_width - shadow_width - diag_offset), tri_top);
119 immVertex2f(pos, floor(frame_x + tri_half_width + shadow_width + 1.0f + diag_offset), tri_top);
120 immVertex2f(pos, frame_x + 0.5f, tri_top - tri_height - diag_offset - shadow_width);
121 GPU_polygon_smooth(false);
122 immEnd();
124
125 /* Vertical line. */
126 if (UI_SCALE_FAC < 0.91f) {
127 shadow_width = 1.0f;
128 rect.xmin = floor(subframe_x) - shadow_width;
129 rect.xmax = rect.xmin + U.pixelsize + shadow_width + shadow_width;
130 }
131 else {
132 rect.xmin = floor(subframe_x - U.pixelsize) - shadow_width;
133 rect.xmax = floor(subframe_x + U.pixelsize + 1.0f) + shadow_width;
134 }
135 rect.ymin = 0.0f;
136 rect.ymax = ceil(scrub_region_rect->ymax - box_margin + shadow_width);
137 UI_draw_roundbox_4fv_ex(&rect, fg_color, nullptr, 1.0f, bg_color, shadow_width, 0.0f);
138 }
139
140 /* Box. */
142 const float box_corner_radius = 4.0f * UI_SCALE_FAC;
143 rect.xmin = frame_x - (box_width / 2.0f);
144 rect.xmax = frame_x + (box_width / 2.0f) + 1.0f;
145 rect.ymin = floor(scrub_region_rect->ymin + (box_margin - shadow_width));
146 rect.ymax = ceil(scrub_region_rect->ymax - box_margin + shadow_width);
148 &rect, fg_color, nullptr, 1.0f, bg_color, shadow_width, box_corner_radius);
149
150 /* Frame number text. */
151 uchar text_color[4];
153 const int y = BLI_rcti_cent_y(scrub_region_rect) - int(fstyle->points * UI_SCALE_FAC * 0.38f);
154 UI_fontstyle_draw_simple(fstyle, frame_x - (text_width / 2.0f), y, frame_str, text_color);
155
156 if (display_stalk) {
157 /* Triangular base under frame number. */
159 GPU_polygon_smooth(true);
161 immUniformColor4fv(fg_color);
162 immVertex2f(pos, frame_x - tri_half_width, tri_top);
163 immVertex2f(pos, frame_x + tri_half_width + 1, tri_top);
164 immVertex2f(pos, frame_x + 0.5f, tri_top - tri_height);
165 immEnd();
167 GPU_polygon_smooth(false);
169 }
170}
171
173 const Scene *scene,
174 bool display_seconds,
175 bool display_stalk)
176{
177 const View2D *v2d = &region->v2d;
180
181 rcti scrub_region_rect;
182 ED_time_scrub_region_rect_get(region, &scrub_region_rect);
183
185 scene, display_seconds, v2d, &scrub_region_rect, scene->r.cfra, display_stalk);
187}
188
189void ED_time_scrub_draw(const ARegion *region,
190 const Scene *scene,
191 bool display_seconds,
192 bool discrete_frames,
193 const int base)
194{
195 const View2D *v2d = &region->v2d;
196
199
200 rcti scrub_region_rect;
201 ED_time_scrub_region_rect_get(region, &scrub_region_rect);
202
203 draw_background(&scrub_region_rect);
204
205 rcti numbers_rect = scrub_region_rect;
206 numbers_rect.ymin = get_centered_text_y(&scrub_region_rect) - 4 * UI_SCALE_FAC;
207 if (discrete_frames) {
209 region, v2d, &numbers_rect, scene, display_seconds, TH_TIME_SCRUB_TEXT, base);
210 }
211 else {
213 region, v2d, &numbers_rect, scene, display_seconds, TH_TIME_SCRUB_TEXT, base);
214 }
215
217}
218
220{
221 rcti clamped_mask = scroller_mask;
222 clamped_mask.ymax -= UI_TIME_SCRUB_MARGIN_Y;
223 return clamped_mask;
224}
225
226bool ED_time_scrub_event_in_region(const ARegion *region, const wmEvent *event)
227{
228 rcti rect = region->winrct;
229 rect.ymin = rect.ymax - UI_TIME_SCRUB_MARGIN_Y;
230 return BLI_rcti_isect_pt_v(&rect, event->xy);
231}
232
234 const ScrArea * /*area*/,
235 const ARegion *region,
236 const wmEvent *event)
237{
238 return ED_time_scrub_event_in_region(region, event);
239}
240
242{
245
246 rcti rect;
247 rect.xmin = 0;
248 rect.xmax = region->winx;
249 rect.ymin = region->winy - UI_TIME_SCRUB_MARGIN_Y;
250 rect.ymax = region->winy;
251
253 immVertexFormat(), "pos", blender::gpu::VertAttrType::SFLOAT_32_32);
256 immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
258
259 PointerRNA ptr = RNA_pointer_create_discrete(&CTX_wm_screen(C)->id, &RNA_DopeSheet, dopesheet);
260
261 const uiStyle *style = UI_style_get_dpi();
262 const float padding_x = 2 * UI_SCALE_FAC;
263 const float padding_y = UI_SCALE_FAC;
264
265 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
266 uiLayout &layout = blender::ui::block_layout(block,
269 rect.xmin + padding_x,
270 rect.ymin + UI_UNIT_Y + padding_y,
271 BLI_rcti_size_x(&rect) - 2 * padding_x,
272 1,
273 0,
274 style);
275 layout.scale_y_set((UI_UNIT_Y - padding_y) / UI_UNIT_Y);
278 layout.prop(&ptr, "filter_text", UI_ITEM_NONE, "", ICON_NONE);
279 layout.prop(&ptr, "use_filter_invert", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
280 UI_block_align_end(block);
282
283 /* Make sure the events are consumed from the search and don't reach other UI blocks since this
284 * is drawn on top of animation-channels. */
287 UI_block_end(C, block);
288 UI_block_draw(C, block);
289
291}
bScreen * CTX_wm_screen(const bContext *C)
float BKE_scene_ctime_get(const Scene *scene)
Definition scene.cc:2370
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
BLI_INLINE int BLI_rcti_cent_y(const struct rcti *rct)
Definition BLI_rect.h:181
size_t size_t size_t BLI_snprintf_utf8(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
unsigned char uchar
unsigned int uint
size_t BLI_timecode_string_from_time(char *str, size_t maxncpy, int brevity_level, float time_seconds, double fps, short timecode_style) ATTR_NONNULL()
Definition timecode.cc:22
#define FRA2TIME(a)
#define UI_SCALE_FAC
void immEnd()
void immUnbindProgram()
void immBindBuiltinProgram(GPUBuiltinShader shader_id)
void immVertex2f(uint attr_id, float x, float y)
void immUniformThemeColor(int color_id)
GPUVertFormat * immVertexFormat()
void immUniformColor4fv(const float rgba[4])
void immBegin(GPUPrimType, uint vertex_len)
void immRectf(uint pos, float x1, float y1, float x2, float y2)
void GPU_matrix_push_projection()
void GPU_matrix_pop_projection()
@ GPU_PRIM_TRIS
@ GPU_SHADER_3D_UNIFORM_COLOR
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_polygon_smooth(bool enable)
Definition gpu_state.cc:83
uint GPU_vertformat_attr_add(GPUVertFormat *format, blender::StringRef name, blender::gpu::VertAttrType type)
#define C
Definition RandGen.cpp:29
#define UI_UNIT_Y
void UI_fontstyle_draw_simple(const uiFontStyle *fs, float x, float y, const char *str, const uchar col[4])
@ UI_BLOCK_CLIP_EVENTS
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
void UI_block_bounds_set_normal(uiBlock *block, int addval)
Definition interface.cc:637
void UI_draw_roundbox_4fv_ex(const rctf *rect, const float inner1[4], const float inner2[4], float shade_dir, const float outline[4], float outline_width, float rad)
const uiStyle * UI_style_get_dpi()
void UI_draw_roundbox_corner_set(int type)
void UI_block_draw(const bContext *C, uiBlock *block)
@ UI_CNR_ALL
void UI_block_align_begin(uiBlock *block)
int UI_fontstyle_string_width(const uiFontStyle *fs, const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define UI_FSTYLE_WIDGET
void UI_block_flag_enable(uiBlock *block, int flag)
void UI_block_end(const bContext *C, uiBlock *block)
void UI_block_align_end(uiBlock *block)
#define UI_ITEM_NONE
@ TH_TIME_SCRUB_BACKGROUND
@ TH_BACK
@ TH_TIME_SCRUB_TEXT
@ TH_CFRAME
@ TH_HEADER_TEXT_HI
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4])
void UI_GetThemeColor4ubv(int colorid, unsigned char col[4])
void UI_view2d_draw_scale_x__discrete_frames_or_seconds(const ARegion *region, const View2D *v2d, const rcti *rect, const Scene *scene, bool display_seconds, int colorid, int base)
#define UI_TIME_SCRUB_MARGIN_Y
Definition UI_view2d.hh:479
void UI_view2d_draw_scale_x__frames_or_seconds(const ARegion *region, const View2D *v2d, const rcti *rect, const Scene *scene, bool display_seconds, int colorid, int base)
float UI_view2d_view_to_region_x(const View2D *v2d, float x)
Definition view2d.cc:1691
#define U
uint pos
#define floor
#define ceil
format
int2 block_layout_resolve(uiBlock *block)
uiLayout & block_layout(uiBlock *block, LayoutDirection direction, LayoutType type, int x, int y, int size, int em, int padding, const uiStyle *style)
void block_layout_set_current(uiBlock *block, uiLayout *layout)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
struct RenderData r
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
void scale_y_set(float scale)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
int xy[2]
Definition WM_types.hh:761
static void get_current_time_str(const Scene *scene, bool display_seconds, int frame, char *r_str, uint str_maxncpy)
rcti ED_time_scrub_clamp_scroller_mask(const rcti &scroller_mask)
static void draw_background(const rcti *rect)
void ED_time_scrub_region_rect_get(const ARegion *region, rcti *r_rect)
void ED_time_scrub_draw(const ARegion *region, const Scene *scene, bool display_seconds, bool discrete_frames, const int base)
void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDopeSheet *dopesheet)
bool ED_time_scrub_event_in_region_poll(const wmWindow *, const ScrArea *, const ARegion *region, const wmEvent *event)
void ED_time_scrub_draw_current_frame(const ARegion *region, const Scene *scene, bool display_seconds, bool display_stalk)
static void draw_current_frame(const Scene *scene, bool display_seconds, const View2D *v2d, const rcti *scrub_region_rect, int current_frame, bool display_stalk=true)
static int get_centered_text_y(const rcti *rect)
bool ED_time_scrub_event_in_region(const ARegion *region, const wmEvent *event)
PointerRNA * ptr
Definition wm_files.cc:4238
void wmOrtho2_region_pixelspace(const ARegion *region)