Blender V4.5
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_rect.h"
14#include "BLI_string_ref.hh"
15
16#include "BLT_translation.hh"
17
18#include "ED_screen.hh"
19#include "ED_undo.hh"
20
21#include "RNA_access.hh"
22#include "RNA_prototypes.hh"
23
24#include "UI_interface.hh"
25#include "interface_intern.hh"
27
30
31static uiBlock *curve_profile_presets_fn(bContext *C, ARegion *region, void *cb_v)
32{
33 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
34 PointerRNA profile_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
35 CurveProfile *profile = static_cast<CurveProfile *>(profile_ptr.data);
36 short yco = 0;
37
38 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
39
40 for (const auto &item :
41 {std::pair<StringRef, eCurveProfilePresets>(IFACE_("Default"), PROF_PRESET_LINE),
42 std::pair<StringRef, eCurveProfilePresets>(
44 std::pair<StringRef, eCurveProfilePresets>(
46 std::pair<StringRef, eCurveProfilePresets>(
48 std::pair<StringRef, eCurveProfilePresets>(CTX_IFACE_(BLT_I18NCONTEXT_ID_MESH, "Steps"),
50 {
51 uiBut *but = uiDefIconTextBut(block,
53 1,
54 ICON_BLANK1,
55 item.first,
56 0,
57 yco -= UI_UNIT_Y,
58 0,
60 nullptr,
61 0.0,
62 0.0,
63 "");
64 const eCurveProfilePresets preset = item.second;
65 UI_but_func_set(but, [profile, cb, preset](bContext &C) {
66 profile->preset = preset;
69 ED_undo_push(&C, "Reset Curve Profile");
71 rna_update_cb(C, cb);
72 });
73 }
74
76 UI_block_bounds_set_text(block, int(3.0f * UI_UNIT_X));
77
78 return block;
79}
80
81static uiBlock *curve_profile_tools_fn(bContext *C, ARegion *region, void *cb_v)
82{
83 RNAUpdateCb &cb = *static_cast<RNAUpdateCb *>(cb_v);
84 PointerRNA profile_ptr = RNA_property_pointer_get(&cb.ptr, cb.prop);
85 CurveProfile *profile = static_cast<CurveProfile *>(profile_ptr.data);
86 short yco = 0;
87
88 uiBlock *block = UI_block_begin(C, region, __func__, blender::ui::EmbossType::Emboss);
89
90 {
91 uiBut *but = uiDefIconTextBut(block,
93 1,
94 ICON_BLANK1,
95 IFACE_("Reset View"),
96 0,
97 yco -= UI_UNIT_Y,
98 0,
100 nullptr,
101 0.0,
102 0.0,
103 "");
104 UI_but_func_set(but, [profile](bContext &C) {
107 });
108 }
109 {
110 uiBut *but = uiDefIconTextBut(block,
112 1,
113 ICON_BLANK1,
114 IFACE_("Reset Curve"),
115 0,
116 yco -= UI_UNIT_Y,
117 0,
118 UI_UNIT_Y,
119 nullptr,
120 0.0,
121 0.0,
122 "");
123 UI_but_func_set(but, [profile, cb](bContext &C) {
124 BKE_curveprofile_reset(profile);
126 ED_undo_push(&C, "Reset Profile");
128 rna_update_cb(C, cb);
129 });
130 }
131
133 UI_block_bounds_set_text(block, int(3.0f * UI_UNIT_X));
134
135 return block;
136}
137
139{
140 return BLI_rctf_size_x(&profile->view_rect) >
142}
143
145{
146 return BLI_rctf_size_x(&profile->view_rect) < BLI_rctf_size_x(&profile->clip_rect);
147}
148
150{
151 if (curve_profile_can_zoom_in(profile)) {
152 const float dx = 0.1154f * BLI_rctf_size_x(&profile->view_rect);
153 profile->view_rect.xmin += dx;
154 profile->view_rect.xmax -= dx;
155 const float dy = 0.1154f * BLI_rctf_size_y(&profile->view_rect);
156 profile->view_rect.ymin += dy;
157 profile->view_rect.ymax -= dy;
158 }
159
161}
162
164{
165 if (curve_profile_can_zoom_out(profile)) {
166 float d = 0.15f * BLI_rctf_size_x(&profile->view_rect);
167 float d1 = d;
168
169 if (profile->flag & PROF_USE_CLIP) {
170 if (profile->view_rect.xmin - d < profile->clip_rect.xmin) {
171 d1 = profile->view_rect.xmin - profile->clip_rect.xmin;
172 }
173 }
174 profile->view_rect.xmin -= d1;
175
176 d1 = d;
177 if (profile->flag & PROF_USE_CLIP) {
178 if (profile->view_rect.xmax + d > profile->clip_rect.xmax) {
179 d1 = -profile->view_rect.xmax + profile->clip_rect.xmax;
180 }
181 }
182 profile->view_rect.xmax += d1;
183
184 d = d1 = 0.15f * BLI_rctf_size_y(&profile->view_rect);
185
186 if (profile->flag & PROF_USE_CLIP) {
187 if (profile->view_rect.ymin - d < profile->clip_rect.ymin) {
188 d1 = profile->view_rect.ymin - profile->clip_rect.ymin;
189 }
190 }
191 profile->view_rect.ymin -= d1;
192
193 d1 = d;
194 if (profile->flag & PROF_USE_CLIP) {
195 if (profile->view_rect.ymax + d > profile->clip_rect.ymax) {
196 d1 = -profile->view_rect.ymax + profile->clip_rect.ymax;
197 }
198 }
199 profile->view_rect.ymax += d1;
200 }
201
203}
204
206{
207 CurveProfile *profile = static_cast<CurveProfile *>(ptr->data);
208 uiBut *bt;
209
210 uiBlock *block = uiLayoutGetBlock(layout);
211
213
214 uiLayoutSetPropSep(layout, false);
215
216 /* Preset selector */
217 /* There is probably potential to use simpler "uiLayout::prop" functions here, but automatic
218 * updating after a preset is selected would be more complicated. */
219 uiLayout *row = &layout->row(true);
220 RNAUpdateCb *presets_cb = MEM_new<RNAUpdateCb>(__func__, cb);
221 bt = uiDefBlockBut(block,
223 presets_cb,
224 IFACE_("Preset"),
225 0,
226 0,
227 UI_UNIT_X,
228 UI_UNIT_X,
229 "");
230 /* Pass ownership of `presets_cb` to the button. */
232 bt,
233 [](bContext *, void *, void *) {},
234 presets_cb,
235 nullptr,
238
239 /* Show a "re-apply" preset button when it has been changed from the preset. */
240 if (profile->flag & PROF_DIRTY_PRESET) {
241 /* Only for dynamic presets. */
243 bt = uiDefIconTextBut(block,
245 0,
246 ICON_NONE,
247 IFACE_("Apply Preset"),
248 0,
249 0,
250 UI_UNIT_X,
251 UI_UNIT_X,
252 nullptr,
253 0.0,
254 0.0,
255 TIP_("Reapply and update the preset, removing changes"));
256 UI_but_func_set(bt, [profile, cb](bContext &C) {
257 BKE_curveprofile_reset(profile);
259 rna_update_cb(C, cb);
260 });
261 }
262 }
263
264 row = &layout->row(false);
265
266 /* (Left aligned) */
267 uiLayout *sub = &row->row(true);
269
270 /* Zoom in */
271 bt = uiDefIconBut(block,
273 0,
274 ICON_ZOOM_IN,
275 0,
276 0,
277 UI_UNIT_X,
278 UI_UNIT_X,
279 nullptr,
280 0.0,
281 0.0,
282 TIP_("Zoom in"));
283 UI_but_func_set(bt, [profile](bContext &C) { curve_profile_zoom_in(&C, profile); });
284 if (!curve_profile_can_zoom_in(profile)) {
285 UI_but_disable(bt, "");
286 }
287
288 /* Zoom out */
289 bt = uiDefIconBut(block,
291 0,
292 ICON_ZOOM_OUT,
293 0,
294 0,
295 UI_UNIT_X,
296 UI_UNIT_X,
297 nullptr,
298 0.0,
299 0.0,
300 TIP_("Zoom out"));
301 UI_but_func_set(bt, [profile](bContext &C) { curve_profile_zoom_out(&C, profile); });
302 if (!curve_profile_can_zoom_out(profile)) {
303 UI_but_disable(bt, "");
304 }
305
306 /* (Right aligned) */
307 sub = &row->row(true);
309
310 /* Flip path */
311 bt = uiDefIconBut(block,
313 0,
314 ICON_ARROW_LEFTRIGHT,
315 0,
316 0,
317 UI_UNIT_X,
318 UI_UNIT_X,
319 nullptr,
320 0.0,
321 0.0,
322 TIP_("Reverse Path"));
323 UI_but_func_set(bt, [profile, cb](bContext &C) {
326 rna_update_cb(C, cb);
327 });
328
329 /* Clipping toggle */
330 const int icon = (profile->flag & PROF_USE_CLIP) ? ICON_CLIPUV_HLT : ICON_CLIPUV_DEHLT;
331 bt = uiDefIconBut(block,
333 0,
334 icon,
335 0,
336 0,
337 UI_UNIT_X,
338 UI_UNIT_X,
339 nullptr,
340 0.0,
341 0.0,
342 TIP_("Toggle Profile Clipping"));
343 UI_but_func_set(bt, [profile, cb](bContext &C) {
344 profile->flag ^= PROF_USE_CLIP;
346 rna_update_cb(C, cb);
347 });
348
349 /* Reset view, reset curve */
350 RNAUpdateCb *tools_cb = MEM_new<RNAUpdateCb>(__func__, cb);
351 bt = uiDefIconBlockBut(block,
353 tools_cb,
354 0,
355 ICON_NONE,
356 0,
357 0,
358 UI_UNIT_X,
359 UI_UNIT_X,
360 TIP_("Tools"));
361 /* Pass ownership of `presets_cb` to the button. */
363 bt,
364 [](bContext *, void *, void *) {},
365 tools_cb,
366 nullptr,
369
370 UI_block_funcN_set(block,
372 MEM_new<RNAUpdateCb>(__func__, cb),
373 nullptr,
376
377 /* The path itself */
378 int path_width = max_ii(uiLayoutGetWidth(layout), UI_UNIT_X);
379 path_width = min_ii(path_width, int(16.0f * UI_UNIT_X));
380 const int path_height = path_width;
381 layout->row(false);
382 uiDefBut(block,
384 0,
385 "",
386 0,
387 0,
388 short(path_width),
389 short(path_height),
390 profile,
391 0.0f,
392 1.0f,
393 "");
394
395 /* Position sliders for (first) selected point */
396 int i;
397 float *selection_x, *selection_y;
398 bool point_last_or_first = false;
399 CurveProfilePoint *point = nullptr;
400 for (i = 0; i < profile->path_len; i++) {
401 if (profile->path[i].flag & PROF_SELECT) {
402 point = &profile->path[i];
403 selection_x = &point->x;
404 selection_y = &point->y;
405 break;
406 }
407 if (profile->path[i].flag & PROF_H1_SELECT) {
408 point = &profile->path[i];
409 selection_x = &point->h1_loc[0];
410 selection_y = &point->h1_loc[1];
411 }
412 else if (profile->path[i].flag & PROF_H2_SELECT) {
413 point = &profile->path[i];
414 selection_x = &point->h2_loc[0];
415 selection_y = &point->h2_loc[1];
416 }
417 }
418 if (ELEM(i, 0, profile->path_len - 1)) {
419 point_last_or_first = true;
420 }
421
422 /* Selected point data */
423 rctf bounds;
424 if (point) {
425 if (profile->flag & PROF_USE_CLIP) {
426 bounds = profile->clip_rect;
427 }
428 else {
429 bounds.xmin = bounds.ymin = -1000.0;
430 bounds.xmax = bounds.ymax = 1000.0;
431 }
432
433 row = &layout->row(true);
434
436 ptr->owner_id, &RNA_CurveProfilePoint, point);
437 PropertyRNA *prop_handle_type = RNA_struct_find_property(&point_ptr, "handle_type_1");
438 row->prop(&point_ptr,
439 prop_handle_type,
441 0,
443 "",
444 ICON_NONE);
445
446 /* Position */
447 bt = uiDefButF(block,
449 0,
450 "X:",
451 0,
452 2 * UI_UNIT_Y,
453 UI_UNIT_X * 10,
454 UI_UNIT_Y,
455 selection_x,
456 bounds.xmin,
457 bounds.xmax,
458 "");
461 UI_but_func_set(bt, [profile, cb](bContext &C) {
463 rna_update_cb(C, cb);
464 });
465 if (point_last_or_first) {
467 }
468 bt = uiDefButF(block,
470 0,
471 "Y:",
472 0,
473 1 * UI_UNIT_Y,
474 UI_UNIT_X * 10,
475 UI_UNIT_Y,
476 selection_y,
477 bounds.ymin,
478 bounds.ymax,
479 "");
482 UI_but_func_set(bt, [profile, cb](bContext &C) {
484 rna_update_cb(C, cb);
485 });
486 if (point_last_or_first) {
488 }
489
490 /* Delete points */
491 bt = uiDefIconBut(block,
493 0,
494 ICON_X,
495 0,
496 0,
497 UI_UNIT_X,
498 UI_UNIT_X,
499 nullptr,
500 0.0,
501 0.0,
502 TIP_("Delete points"));
503 UI_but_func_set(bt, [profile, cb](bContext &C) {
506 rna_update_cb(C, cb);
507 });
508 if (point_last_or_first) {
510 }
511 }
512
513 layout->prop(ptr, "use_sample_straight_edges", UI_ITEM_NONE, std::nullopt, ICON_NONE);
514 layout->prop(ptr, "use_sample_even_lengths", UI_ITEM_NONE, std::nullopt, ICON_NONE);
515
516 UI_block_funcN_set(block, nullptr, nullptr, nullptr);
517}
518
520{
521 PropertyRNA *prop = RNA_struct_find_property(ptr, propname.c_str());
522
523 uiBlock *block = uiLayoutGetBlock(layout);
524
525 if (!prop) {
526 RNA_warning("Curve Profile property not found: %s.%s",
528 propname.c_str());
529 return;
530 }
531
532 if (RNA_property_type(prop) != PROP_POINTER) {
533 RNA_warning("Curve Profile is not a pointer: %s.%s",
535 propname.c_str());
536 return;
537 }
538
540 if (!cptr.data || !RNA_struct_is_a(cptr.type, &RNA_CurveProfile)) {
541 return;
542 }
543
544 ID *id = cptr.owner_id;
546
547 CurveProfile_buttons_layout(layout, &cptr, RNAUpdateCb{*ptr, prop});
548
549 UI_block_lock_clear(block);
550}
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
@ 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:639
void ED_undo_push(bContext *C, const char *str)
Definition ed_undo.cc:99
#define RNA_warning(format,...)
@ PROP_POINTER
Definition RNA_types.hh:155
#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)
void UI_but_disable(uiBut *but, const char *disabled_hint)
#define UI_UNIT_Y
uiBut * uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, blender::StringRef str, int x, int y, short width, short height, void *poin, float min, float max, std::optional< blender::StringRef > tip)
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)
uiBut * uiDefBut(uiBlock *block, int 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_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)
uiBut * uiDefIconBut(uiBlock *block, int 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_block_bounds_set_text(uiBlock *block, int addval)
Definition interface.cc:635
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)
@ UI_DIR_DOWN
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)
@ UI_BTYPE_BUT
@ UI_BTYPE_BUT_MENU
@ UI_BTYPE_NUM
@ UI_BTYPE_CURVEPROFILE
@ UI_BUT_DISABLED
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)
uiBut * uiDefButF(uiBlock *block, int 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_block_lock_set(uiBlock *block, bool val, const char *lockstr)
void UI_but_flag_enable(uiBut *but, int flag)
@ UI_ITEM_R_EXPAND
@ UI_ITEM_R_ICON_ONLY
uiBlock * uiLayoutGetBlock(uiLayout *layout)
@ UI_LAYOUT_ALIGN_LEFT
@ UI_LAYOUT_ALIGN_RIGHT
void uiLayoutSetAlignment(uiLayout *layout, char alignment)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
int uiLayoutGetWidth(uiLayout *layout)
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
constexpr const char * c_str() const
#define SELECT
#define ID_IS_EDITABLE(_id)
#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:404
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
uiLayout & row(bool align)
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:4227