1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2019 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edanimation
22 */
23
24 #include "BKE_context.h"
25
26 #include "GPU_immediate.h"
27 #include "GPU_matrix.h"
28 #include "GPU_state.h"
29
30 #include "ED_time_scrub_ui.h"
31
32 #include "WM_api.h"
33 #include "WM_types.h"
34
35 #include "UI_interface.h"
36 #include "UI_interface_icons.h"
37 #include "UI_resources.h"
38 #include "UI_view2d.h"
39
40 #include "DNA_scene_types.h"
41
42 #include "BLI_math.h"
43 #include "BLI_rect.h"
44 #include "BLI_string.h"
45 #include "BLI_timecode.h"
46
47 #include "RNA_access.h"
48
get_time_scrub_region_rect(const ARegion * region,rcti * rect)49 static void get_time_scrub_region_rect(const ARegion *region, rcti *rect)
50 {
51 rect->xmin = 0;
52 rect->xmax = region->winx;
53 rect->ymax = region->winy;
54 rect->ymin = rect->ymax - UI_TIME_SCRUB_MARGIN_Y;
55 }
56
get_centered_text_y(const rcti * rect)57 static int get_centered_text_y(const rcti *rect)
58 {
59 return BLI_rcti_cent_y(rect) - UI_DPI_FAC * 4;
60 }
61
draw_background(const rcti * rect)62 static void draw_background(const rcti *rect)
63 {
64 uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
65 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
66
67 immUniformThemeColor(TH_TIME_SCRUB_BACKGROUND);
68
69 GPU_blend(GPU_BLEND_ALPHA);
70
71 immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
72
73 GPU_blend(GPU_BLEND_NONE);
74
75 immUnbindProgram();
76 }
77
get_current_time_str(const Scene * scene,bool display_seconds,int frame,uint max_len,char * r_str)78 static void get_current_time_str(
79 const Scene *scene, bool display_seconds, int frame, uint max_len, char *r_str)
80 {
81 if (display_seconds) {
82 BLI_timecode_string_from_time(r_str, max_len, 0, FRA2TIME(frame), FPS, U.timecode_style);
83 }
84 else {
85 BLI_snprintf(r_str, max_len, "%d", frame);
86 }
87 }
88
draw_current_frame(const Scene * scene,bool display_seconds,const View2D * v2d,const rcti * scrub_region_rect,int current_frame,float sub_frame,bool draw_line)89 static void draw_current_frame(const Scene *scene,
90 bool display_seconds,
91 const View2D *v2d,
92 const rcti *scrub_region_rect,
93 int current_frame,
94 float sub_frame,
95 bool draw_line)
96 {
97 const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
98 int frame_x = UI_view2d_view_to_region_x(v2d, current_frame);
99
100 char frame_str[64];
101 get_current_time_str(scene, display_seconds, current_frame, sizeof(frame_str), frame_str);
102 float text_width = UI_fontstyle_string_width(fstyle, frame_str);
103 float box_width = MAX2(text_width + 8 * UI_DPI_FAC, 24 * UI_DPI_FAC);
104 float box_padding = 3 * UI_DPI_FAC;
105
106 float bg_color[4];
107 UI_GetThemeColorShade4fv(TH_CFRAME, -5, bg_color);
108
109 if (draw_line) {
110 /* Draw vertical line to from the bottom of the current frame box to the bottom of the screen.
111 */
112 const float subframe_x = UI_view2d_view_to_region_x(v2d, current_frame + sub_frame);
113 GPUVertFormat *format = immVertexFormat();
114 uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
115 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
116 immUniformThemeColor(TH_CFRAME);
117 immRectf(pos,
118 subframe_x - U.pixelsize,
119 scrub_region_rect->ymax - box_padding,
120 subframe_x + U.pixelsize,
121 0.0f);
122 immUnbindProgram();
123 }
124
125 UI_draw_roundbox_corner_set(UI_CNR_ALL);
126
127 UI_draw_roundbox_3fv_alpha(true,
128 frame_x - box_width / 2 + U.pixelsize / 2,
129 scrub_region_rect->ymin + box_padding,
130 frame_x + box_width / 2 + U.pixelsize / 2,
131 scrub_region_rect->ymax - box_padding,
132 4 * UI_DPI_FAC,
133 bg_color,
134 1.0f);
135
136 UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color);
137 UI_draw_roundbox_aa(false,
138 frame_x - box_width / 2 + U.pixelsize / 2,
139 scrub_region_rect->ymin + box_padding,
140 frame_x + box_width / 2 + U.pixelsize / 2,
141 scrub_region_rect->ymax - box_padding,
142 4 * UI_DPI_FAC,
143 bg_color);
144
145 uchar text_color[4];
146 UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color);
147 UI_fontstyle_draw_simple(fstyle,
148 frame_x - text_width / 2 + U.pixelsize / 2,
149 get_centered_text_y(scrub_region_rect),
150 frame_str,
151 text_color);
152 }
153
ED_time_scrub_draw_current_frame(const ARegion * region,const Scene * scene,bool display_seconds,bool draw_line)154 void ED_time_scrub_draw_current_frame(const ARegion *region,
155 const Scene *scene,
156 bool display_seconds,
157 bool draw_line)
158 {
159 const View2D *v2d = ®ion->v2d;
160 GPU_matrix_push_projection();
161 wmOrtho2_region_pixelspace(region);
162
163 rcti scrub_region_rect;
164 get_time_scrub_region_rect(region, &scrub_region_rect);
165
166 draw_current_frame(scene,
167 display_seconds,
168 v2d,
169 &scrub_region_rect,
170 scene->r.cfra,
171 scene->r.subframe,
172 draw_line);
173 GPU_matrix_pop_projection();
174 }
175
ED_time_scrub_draw(const ARegion * region,const Scene * scene,bool display_seconds,bool discrete_frames)176 void ED_time_scrub_draw(const ARegion *region,
177 const Scene *scene,
178 bool display_seconds,
179 bool discrete_frames)
180 {
181 const View2D *v2d = ®ion->v2d;
182
183 GPU_matrix_push_projection();
184 wmOrtho2_region_pixelspace(region);
185
186 rcti scrub_region_rect;
187 get_time_scrub_region_rect(region, &scrub_region_rect);
188
189 draw_background(&scrub_region_rect);
190
191 rcti numbers_rect = scrub_region_rect;
192 numbers_rect.ymin = get_centered_text_y(&scrub_region_rect) - 4 * UI_DPI_FAC;
193 if (discrete_frames) {
194 UI_view2d_draw_scale_x__discrete_frames_or_seconds(
195 region, v2d, &numbers_rect, scene, display_seconds, TH_TEXT);
196 }
197 else {
198 UI_view2d_draw_scale_x__frames_or_seconds(
199 region, v2d, &numbers_rect, scene, display_seconds, TH_TEXT);
200 }
201
202 GPU_matrix_pop_projection();
203 }
204
ED_time_scrub_event_in_region(const ARegion * region,const wmEvent * event)205 bool ED_time_scrub_event_in_region(const ARegion *region, const wmEvent *event)
206 {
207 rcti rect = region->winrct;
208 rect.ymin = rect.ymax - UI_TIME_SCRUB_MARGIN_Y;
209 return BLI_rcti_isect_pt(&rect, event->x, event->y);
210 }
211
ED_time_scrub_channel_search_draw(const bContext * C,ARegion * region,bDopeSheet * dopesheet)212 void ED_time_scrub_channel_search_draw(const bContext *C, ARegion *region, bDopeSheet *dopesheet)
213 {
214 GPU_matrix_push_projection();
215 wmOrtho2_region_pixelspace(region);
216
217 rcti rect;
218 rect.xmin = 0;
219 rect.xmax = region->winx;
220 rect.ymin = region->winy - UI_TIME_SCRUB_MARGIN_Y;
221 rect.ymax = region->winy;
222
223 uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
224 immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
225 immUniformThemeColor(TH_BACK);
226 immRectf(pos, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
227 immUnbindProgram();
228
229 PointerRNA ptr;
230 RNA_pointer_create(&CTX_wm_screen(C)->id, &RNA_DopeSheet, dopesheet, &ptr);
231
232 const uiStyle *style = UI_style_get_dpi();
233 const float padding_x = 2 * UI_DPI_FAC;
234 const float padding_y = UI_DPI_FAC;
235
236 uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
237 uiLayout *layout = UI_block_layout(block,
238 UI_LAYOUT_VERTICAL,
239 UI_LAYOUT_HEADER,
240 rect.xmin + padding_x,
241 rect.ymin + UI_UNIT_Y + padding_y,
242 BLI_rcti_size_x(&rect) - 2 * padding_x,
243 1,
244 0,
245 style);
246 uiLayoutSetScaleY(layout, (UI_UNIT_Y - padding_y) / UI_UNIT_Y);
247 UI_block_layout_set_current(block, layout);
248 UI_block_align_begin(block);
249 uiItemR(layout, &ptr, "filter_text", 0, "", ICON_NONE);
250 uiItemR(layout, &ptr, "use_filter_invert", 0, "", ICON_ARROW_LEFTRIGHT);
251 UI_block_align_end(block);
252 UI_block_layout_resolve(block, NULL, NULL);
253
254 UI_block_end(C, block);
255 UI_block_draw(C, block);
256
257 GPU_matrix_pop_projection();
258 }
259