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 = &region->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 = &region->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