Blender V5.0
interface_template_curve_profile.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BKE_context.hh"
10#include "BKE_curveprofile.h"
11#include "BKE_library.hh"
12
13#include "BLI_math_base.h"
14#include "BLI_rect.h"
15#include "BLI_string_ref.hh"
16
17#include "BLT_translation.hh"
18
19#include "ED_screen.hh"
20#include "ED_undo.hh"
21
22#include "RNA_access.hh"
23#include "RNA_prototypes.hh"
24
26#include "interface_intern.hh"
28
31
32static uiBlock *curve_profile_presets_fn(bContext *C, ARegion *region, void *cb_v)
33{
34 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
35 PointerRNA profile_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
36 CurveProfile *profile = static_cast<CurveProfile *>(profile_ptr.data);
37 short yco = 0;
38
39 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
40
41 for (const auto &item :
42 {std::pair<StringRef, eCurveProfilePresets>(IFACE_("Default"), PROF_PRESET_LINE),
43 std::pair<StringRef, eCurveProfilePresets>(
45 std::pair<StringRef, eCurveProfilePresets>(
47 std::pair<StringRef, eCurveProfilePresets>(
49 std::pair<StringRef, eCurveProfilePresets>(CTX_IFACE_(BLT_I18NCONTEXT_ID_MESH, "Steps"),
51 {
52 uiBut *but = uiDefIconTextBut(block,
54 1,
55 ICON_BLANK1,
56 item.first,
57 0,
58 yco -= UI_UNIT_Y,
59 0,
61 nullptr,
62 "");
63 const eCurveProfilePresets preset = item.second;
64 UI_but_func_set(but, [profile, cb, preset](bContext &C) {
65 profile->preset = preset;
68 ED_undo_push(&C, "Reset Curve Profile");
70 rna_update_cb(C, cb);
71 });
72 }
73
75 UI_block_bounds_set_text(block, int(3.0f * UI_UNIT_X));
76
77 return block;
78}
79
80static uiBlock *curve_profile_tools_fn(bContext *C, ARegion *region, void *cb_v)
81{
82 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
83 PointerRNA profile_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
84 CurveProfile *profile = static_cast<CurveProfile *>(profile_ptr.data);
85 short yco = 0;
86
87 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
88
89 {
90 uiBut *but = uiDefIconTextBut(block,
92 1,
93 ICON_BLANK1,
94 IFACE_("Reset View"),
95 0,
96 yco -= UI_UNIT_Y,
97 0,
99 nullptr,
100 "");
101 UI_but_func_set(but, [profile](bContext &C) {
104 });
105 }
106 {
107 uiBut *but = uiDefIconTextBut(block,
109 1,
110 ICON_BLANK1,
111 IFACE_("Reset Curve"),
112 0,
113 yco -= UI_UNIT_Y,
114 0,
115 UI_UNIT_Y,
116 nullptr,
117 "");
118 UI_but_func_set(but, [profile, cb](bContext &C) {
119 BKE_curveprofile_reset(profile);
121 ED_undo_push(&C, "Reset Profile");
123 rna_update_cb(C, cb);
124 });
125 }
126
128 UI_block_bounds_set_text(block, int(3.0f * UI_UNIT_X));
129
130 return block;
131}
132
134{
135 return BLI_rctf_size_x(&profile->view_rect) >
137}
138
140{
141 return BLI_rctf_size_x(&profile->view_rect) < BLI_rctf_size_x(&profile->clip_rect);
142}
143
145{
146 if (curve_profile_can_zoom_in(profile)) {
147 const float dx = 0.1154f * BLI_rctf_size_x(&profile->view_rect);
148 profile->view_rect.xmin += dx;
149 profile->view_rect.xmax -= dx;
150 const float dy = 0.1154f * BLI_rctf_size_y(&profile->view_rect);
151 profile->view_rect.ymin += dy;
152 profile->view_rect.ymax -= dy;
153 }
154
156}
157
159{
160 if (curve_profile_can_zoom_out(profile)) {
161 float d = 0.15f * BLI_rctf_size_x(&profile->view_rect);
162 float d1 = d;
163
164 if (profile->flag & PROF_USE_CLIP) {
165 if (profile->view_rect.xmin - d < profile->clip_rect.xmin) {
166 d1 = profile->view_rect.xmin - profile->clip_rect.xmin;
167 }
168 }
169 profile->view_rect.xmin -= d1;
170
171 d1 = d;
172 if (profile->flag & PROF_USE_CLIP) {
173 if (profile->view_rect.xmax + d > profile->clip_rect.xmax) {
174 d1 = -profile->view_rect.xmax + profile->clip_rect.xmax;
175 }
176 }
177 profile->view_rect.xmax += d1;
178
179 d = d1 = 0.15f * BLI_rctf_size_y(&profile->view_rect);
180
181 if (profile->flag & PROF_USE_CLIP) {
182 if (profile->view_rect.ymin - d < profile->clip_rect.ymin) {
183 d1 = profile->view_rect.ymin - profile->clip_rect.ymin;
184 }
185 }
186 profile->view_rect.ymin -= d1;
187
188 d1 = d;
189 if (profile->flag & PROF_USE_CLIP) {
190 if (profile->view_rect.ymax + d > profile->clip_rect.ymax) {
191 d1 = -profile->view_rect.ymax + profile->clip_rect.ymax;
192 }
193 }
194 profile->view_rect.ymax += d1;
195 }
196
198}
199
201{
202 CurveProfile *profile = static_cast<CurveProfile *>(ptr->data);
203 uiBut *bt;
204
205 uiBlock *block = layout->block();
206
208
209 layout->use_property_split_set(false);
210
211 /* Preset selector */
212 /* There is probably potential to use simpler "uiLayout::prop" functions here, but automatic
213 * updating after a preset is selected would be more complicated. */
214 uiLayout *row = &layout->row(true);
215 RNAUpdateCb *presets_cb = MEM_new<RNAUpdateCb>(__func__, cb);
216 bt = uiDefBlockBut(block,
218 presets_cb,
219 IFACE_("Preset"),
220 0,
221 0,
222 UI_UNIT_X,
223 UI_UNIT_X,
224 "");
225 /* Pass ownership of `presets_cb` to the button. */
227 bt,
228 [](bContext *, void *, void *) {},
229 presets_cb,
230 nullptr,
233
234 /* Show a "re-apply" preset button when it has been changed from the preset. */
235 if (profile->flag & PROF_DIRTY_PRESET) {
236 /* Only for dynamic presets. */
238 bt = uiDefIconTextBut(block,
240 0,
241 ICON_NONE,
242 IFACE_("Apply Preset"),
243 0,
244 0,
245 UI_UNIT_X,
246 UI_UNIT_X,
247 nullptr,
248 TIP_("Reapply and update the preset, removing changes"));
249 UI_but_func_set(bt, [profile, cb](bContext &C) {
250 BKE_curveprofile_reset(profile);
252 rna_update_cb(C, cb);
253 });
254 }
255 }
256
257 row = &layout->row(false);
258
259 /* (Left aligned) */
260 uiLayout *sub = &row->row(true);
262
263 /* Zoom in */
264 bt = uiDefIconBut(block,
266 0,
267 ICON_ZOOM_IN,
268 0,
269 0,
270 UI_UNIT_X,
271 UI_UNIT_X,
272 nullptr,
273 0.0,
274 0.0,
275 TIP_("Zoom in"));
276 UI_but_func_set(bt, [profile](bContext &C) { curve_profile_zoom_in(&C, profile); });
277 if (!curve_profile_can_zoom_in(profile)) {
278 UI_but_disable(bt, "");
279 }
280
281 /* Zoom out */
282 bt = uiDefIconBut(block,
284 0,
285 ICON_ZOOM_OUT,
286 0,
287 0,
288 UI_UNIT_X,
289 UI_UNIT_X,
290 nullptr,
291 0.0,
292 0.0,
293 TIP_("Zoom out"));
294 UI_but_func_set(bt, [profile](bContext &C) { curve_profile_zoom_out(&C, profile); });
295 if (!curve_profile_can_zoom_out(profile)) {
296 UI_but_disable(bt, "");
297 }
298
299 /* (Right aligned) */
300 sub = &row->row(true);
302
303 /* Flip path */
304 bt = uiDefIconBut(block,
306 0,
307 ICON_ARROW_LEFTRIGHT,
308 0,
309 0,
310 UI_UNIT_X,
311 UI_UNIT_X,
312 nullptr,
313 0.0,
314 0.0,
315 TIP_("Reverse Path"));
316 UI_but_func_set(bt, [profile, cb](bContext &C) {
319 rna_update_cb(C, cb);
320 });
321
322 /* Clipping toggle */
323 const int icon = (profile->flag & PROF_USE_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
324 bt = uiDefIconBut(block,
326 0,
327 icon,
328 0,
329 0,
330 UI_UNIT_X,
331 UI_UNIT_X,
332 nullptr,
333 0.0,
334 0.0,
335 TIP_("Toggle Profile Clipping"));
336 UI_but_func_set(bt, [profile, cb](bContext &C) {
337 profile->flag ^= PROF_USE_CLIP;
339 rna_update_cb(C, cb);
340 });
341
342 /* Reset view, reset curve */
343 RNAUpdateCb *tools_cb = MEM_new<RNAUpdateCb>(__func__, cb);
344 bt = uiDefIconBlockBut(block,
346 tools_cb,
347 0,
348 ICON_NONE,
349 0,
350 0,
351 UI_UNIT_X,
352 UI_UNIT_X,
353 TIP_("Tools"));
354 /* Pass ownership of `presets_cb` to the button. */
356 bt,
357 [](bContext *, void *, void *) {},
358 tools_cb,
359 nullptr,
362
363 UI_block_funcN_set(block,
365 MEM_new<RNAUpdateCb>(__func__, cb),
366 nullptr,
369
370 /* The path itself */
371 int path_width = max_ii(layout->width(), UI_UNIT_X);
372 path_width = min_ii(path_width, int(16.0f * UI_UNIT_X));
373 const int path_height = path_width;
374 layout->row(false);
375 uiDefBut(block,
377 0,
378 "",
379 0,
380 0,
381 short(path_width),
382 short(path_height),
383 profile,
384 0.0f,
385 1.0f,
386 "");
387
388 /* Position sliders for (first) selected point */
389 int i;
390 float *selection_x, *selection_y;
391 bool point_last_or_first = false;
392 CurveProfilePoint *point = nullptr;
393 for (i = 0; i < profile->path_len; i++) {
394 if (profile->path[i].flag & PROF_SELECT) {
395 point = &profile->path[i];
396 selection_x = &point->x;
397 selection_y = &point->y;
398 break;
399 }
400 if (profile->path[i].flag & PROF_H1_SELECT) {
401 point = &profile->path[i];
402 selection_x = &point->h1_loc[0];
403 selection_y = &point->h1_loc[1];
404 }
405 else if (profile->path[i].flag & PROF_H2_SELECT) {
406 point = &profile->path[i];
407 selection_x = &point->h2_loc[0];
408 selection_y = &point->h2_loc[1];
409 }
410 }
411 if (ELEM(i, 0, profile->path_len - 1)) {
412 point_last_or_first = true;
413 }
414
415 /* Selected point data */
416 rctf bounds;
417 if (point) {
418 if (profile->flag & PROF_USE_CLIP) {
419 bounds = profile->clip_rect;
420 }
421 else {
422 bounds.xmin = bounds.ymin = -1000.0;
423 bounds.xmax = bounds.ymax = 1000.0;
424 }
425
426 row = &layout->row(true);
427
429 ptr->owner_id, &RNA_CurveProfilePoint, point);
430 PropertyRNA *prop_handle_type = RNA_struct_find_property(&point_ptr, "handle_type_1");
431 row->prop(&point_ptr,
432 prop_handle_type,
434 0,
436 "",
437 ICON_NONE);
438
439 /* Position */
440 bt = uiDefButF(block,
442 0,
443 "X:",
444 0,
445 2 * UI_UNIT_Y,
446 UI_UNIT_X * 10,
447 UI_UNIT_Y,
448 selection_x,
449 bounds.xmin,
450 bounds.xmax,
451 "");
454 UI_but_func_set(bt, [profile, cb](bContext &C) {
456 rna_update_cb(C, cb);
457 });
458 if (point_last_or_first) {
460 }
461 bt = uiDefButF(block,
463 0,
464 "Y:",
465 0,
466 1 * UI_UNIT_Y,
467 UI_UNIT_X * 10,
468 UI_UNIT_Y,
469 selection_y,
470 bounds.ymin,
471 bounds.ymax,
472 "");
475 UI_but_func_set(bt, [profile, cb](bContext &C) {
477 rna_update_cb(C, cb);
478 });
479 if (point_last_or_first) {
481 }
482
483 /* Delete points */
484 bt = uiDefIconBut(block,
486 0,
487 ICON_X,
488 0,
489 0,
490 UI_UNIT_X,
491 UI_UNIT_X,
492 nullptr,
493 0.0,
494 0.0,
495 TIP_("Delete points"));
496 UI_but_func_set(bt, [profile, cb](bContext &C) {
499 rna_update_cb(C, cb);
500 });
501 if (point_last_or_first) {
503 }
504 }
505
506 layout->prop(ptr, "use_sample_straight_edges", UI_ITEM_NONE, std::nullopt, ICON_NONE);
507 layout->prop(ptr, "use_sample_even_lengths", UI_ITEM_NONE, std::nullopt, ICON_NONE);
508
509 UI_block_funcN_set(block, nullptr, nullptr, nullptr);
510}
511
513{
514 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
515
516 uiBlock *block = layout->block();
517
518 if (!prop) {
519 RNA_warning("Curve Profile property not found: %s.%s",
521 propname.c_str());
522 return;
523 }
524
525 if (RNA_property_type(prop) != PROP_POINTER) {
526 RNA_warning("Curve Profile is not a pointer: %s.%s",
528 propname.c_str());
529 return;
530 }
531
533 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveProfile)) {
534 return;
535 }
536
537 ID *id = cptr.owner_id;
539
540 CurveProfile_buttons_layout(layout, &cptr, RNAUpdateCb{*ptr, prop});
541
542 UI_block_lock_clear(block);
543}
ARegion * CTX_wm_region(const bContext *C)
void BKE_curveprofile_update(struct CurveProfile *profile, int update_flags)
@ PROF_UPDATE_CLIP
@ PROF_UPDATE_REMOVE_DOUBLES
@ PROF_UPDATE_NONE
void BKE_curveprofile_reset_view(struct CurveProfile *profile)
void BKE_curveprofile_remove_by_flag(struct CurveProfile *profile, short flag)
void BKE_curveprofile_reset(struct CurveProfile *profile)
void BKE_curveprofile_reverse(struct CurveProfile *profile)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition BLI_rect.h:202
BLI_INLINE float BLI_rctf_size_y(const struct rctf *rct)
Definition BLI_rect.h:206
#define ELEM(...)
#define TIP_(msgid)
#define CTX_IFACE_(context, msgid)
#define IFACE_(msgid)
#define BLT_I18NCONTEXT_ID_MESH
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ PROF_PRESET_CROWN
@ PROF_PRESET_LINE
@ PROF_PRESET_CORNICE
@ PROF_PRESET_SUPPORTS
@ PROF_PRESET_STEPS
@ PROF_DIRTY_PRESET
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:618
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:98
#define RNA_warning(format,...)
@ PROP_POINTER
Definition RNA_types.hh:167
#define C
Definition RandGen.cpp:29
void UI_but_func_set(uiBut *but, std::function< void(bContext &)> func)
void * but_func_argN_copy(const void *argN)
void but_func_argN_free(void *argN)
uiBut * uiDefButF(uiBlock *block, ButType type, int retval, blender::StringRef str, int x, int y, short width, short height, float *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_disable(uiBut *but, const char *disabled_hint)
uiBut * uiDefIconTextBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, std::optional< blender::StringRef > tip)
#define UI_UNIT_Y
void UI_block_emboss_set(uiBlock *block, blender::ui::EmbossType emboss)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
void UI_block_lock_clear(uiBlock *block)
@ UI_BUT_DISABLED
uiBut * uiDefIconBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, int icon, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_number_step_size_set(uiBut *but, float step_size)
uiBut * uiDefBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, blender::StringRef str, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_block_bounds_set_text(uiBlock *block, int addval)
Definition interface.cc:647
void UI_block_funcN_set(uiBlock *block, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
void UI_but_number_precision_set(uiBut *but, float precision)
void UI_block_direction_set(uiBlock *block, char direction)
#define UI_UNIT_X
uiBut * uiDefIconBlockBut(uiBlock *block, uiBlockCreateFunc func, void *arg, int retval, int icon, int x, int y, short width, short height, std::optional< blender::StringRef > tip)
void UI_but_funcN_set(uiBut *but, uiButHandleNFunc funcN, void *argN, void *arg2, uiButArgNFree func_argN_free_fn=MEM_freeN, uiButArgNCopy func_argN_copy_fn=MEM_dupallocN)
void UI_block_lock_set(uiBlock *block, bool val, const char *lockstr)
uiBut * uiDefBut(uiBlock *block, uiButTypeWithPointerType but_and_ptr_type, int retval, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
void UI_but_flag_enable(uiBut *but, int flag)
@ UI_DIR_DOWN
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_ICON_ONLY
#define UI_ITEM_NONE
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
constexpr const char * c_str() const
#define SELECT
#define RNA_NO_INDEX
void uiTemplateCurveProfile(uiLayout *layout, PointerRNA *ptr, const StringRefNull propname)
static void CurveProfile_buttons_layout(uiLayout *layout, PointerRNA *ptr, const RNAUpdateCb &cb)
static bool curve_profile_can_zoom_out(CurveProfile *profile)
static uiBlock * curve_profile_presets_fn(bContext *C, ARegion *region, void *cb_v)
static uiBlock * curve_profile_tools_fn(bContext *C, ARegion *region, void *cb_v)
static bool curve_profile_can_zoom_in(CurveProfile *profile)
static void curve_profile_zoom_out(bContext *C, CurveProfile *profile)
static void curve_profile_zoom_in(bContext *C, CurveProfile *profile)
#define CURVE_ZOOM_MAX
static void rna_update_cb(bContext &C, const RNAUpdateCb &cb)
#define ERROR_LIBDATA_MESSAGE
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PropertyType RNA_property_type(PropertyRNA *prop)
PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop)
const char * RNA_struct_identifier(const StructRNA *type)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
CurveProfilePoint * path
Definition DNA_ID.h:414
ID * owner_id
Definition RNA_types.hh:51
StructRNA * type
Definition RNA_types.hh:52
void * data
Definition RNA_types.hh:53
float xmax
float xmin
float ymax
float ymin
void alignment_set(blender::ui::LayoutAlign alignment)
uiBlock * block() const
int width() const
uiLayout & row(bool align)
void use_property_split_set(bool value)
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)
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238