BoidState *boid_duplicate_state(BoidSettings *boids, BoidState *state) { BoidState *staten = MEM_dupallocN(state); BLI_duplicatelist(&staten->rules, &state->rules); BLI_duplicatelist(&staten->conditions, &state->conditions); BLI_duplicatelist(&staten->actions, &state->actions); staten->id = boids->last_state_id++; return staten; }
/** * Allocate a new pose on the heap, and copy the src pose and it's channels * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL. * * \param dst Should be freed already, makes entire duplicate. */ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints) { bPose *outPose; bPoseChannel *pchan; ListBase listb; if (!src) { *dst = NULL; return; } outPose = MEM_callocN(sizeof(bPose), "pose"); BLI_duplicatelist(&outPose->chanbase, &src->chanbase); outPose->iksolver = src->iksolver; outPose->ikdata = NULL; outPose->ikparam = MEM_dupallocN(src->ikparam); outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->custom) { id_us_plus(&pchan->custom->id); } /* warning, O(n2) here, but it's a rarely used feature. */ if (pchan->custom_tx) { pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name); } if (copy_constraints) { BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } if (pchan->prop) { pchan->prop = IDP_CopyProperty(pchan->prop); } } /* for now, duplicate Bone Groups too when doing this */ if (copy_constraints) { BLI_duplicatelist(&outPose->agroups, &src->agroups); } *dst = outPose; }
ARegion *BKE_area_region_copy(SpaceType *st, ARegion *ar) { ARegion *newar = MEM_dupallocN(ar); Panel *pa, *newpa, *patab; newar->prev = newar->next = NULL; BLI_listbase_clear(&newar->handlers); BLI_listbase_clear(&newar->uiblocks); BLI_listbase_clear(&newar->panels_category); BLI_listbase_clear(&newar->panels_category_active); BLI_listbase_clear(&newar->ui_lists); newar->swinid = 0; /* use optional regiondata callback */ if (ar->regiondata) { ARegionType *art = BKE_regiontype_from_id(st, ar->regiontype); if (art && art->duplicate) newar->regiondata = art->duplicate(ar->regiondata); else newar->regiondata = MEM_dupallocN(ar->regiondata); } if (ar->v2d.tab_offset) newar->v2d.tab_offset = MEM_dupallocN(ar->v2d.tab_offset); BLI_listbase_clear(&newar->panels); BLI_duplicatelist(&newar->panels, &ar->panels); BLI_listbase_clear(&newar->ui_previews); BLI_duplicatelist(&newar->ui_previews, &ar->ui_previews); /* copy panel pointers */ for (newpa = newar->panels.first; newpa; newpa = newpa->next) { patab = newar->panels.first; pa = ar->panels.first; while (patab) { if (newpa->paneltab == pa) { newpa->paneltab = patab; break; } patab = patab->next; pa = pa->next; } } return newar; }
static int vertex_group_copy_to_linked_exec(bContext *C, wmOperator *op) { Scene *scene= CTX_data_scene(C); Object *ob= CTX_data_pointer_get_type(C, "object", &RNA_Object).data; Base *base; int retval= OPERATOR_CANCELLED; for(base=scene->base.first; base; base= base->next) { if(base->object->type==ob->type) { if(base->object!=ob && base->object->data==ob->data) { BLI_freelistN(&base->object->defbase); BLI_duplicatelist(&base->object->defbase, &ob->defbase); base->object->actdef= ob->actdef; DAG_id_flush_update(&base->object->id, OB_RECALC_DATA); WM_event_add_notifier(C, NC_OBJECT|ND_DRAW, base->object); WM_event_add_notifier(C, NC_GEOM|ND_DATA, base->object->data); retval = OPERATOR_FINISHED; } } } return retval; }
bContextStore *CTX_store_add_all(ListBase *contexts, bContextStore *context) { bContextStoreEntry *entry, *tentry; bContextStore *ctx, *lastctx; /* ensure we have a context to put the entries in, if it was already used * we have to copy the context to ensure */ ctx = contexts->last; if (!ctx || ctx->used) { if (ctx) { lastctx = ctx; ctx = MEM_dupallocN(lastctx); BLI_duplicatelist(&ctx->entries, &lastctx->entries); } else ctx = MEM_callocN(sizeof(bContextStore), "bContextStore"); BLI_addtail(contexts, ctx); } for (tentry = context->entries.first; tentry; tentry = tentry->next) { entry = MEM_dupallocN(tentry); BLI_addtail(&ctx->entries, entry); } return ctx; }
/* Duplicate all of the F-Modifiers in the Modifier stacks */ void copy_fmodifiers(ListBase *dst, const ListBase *src) { FModifier *fcm, *srcfcm; if (ELEM(NULL, dst, src)) { return; } BLI_listbase_clear(dst); BLI_duplicatelist(dst, src); for (fcm = dst->first, srcfcm = src->first; fcm && srcfcm; srcfcm = srcfcm->next, fcm = fcm->next) { const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); /* make a new copy of the F-Modifier's data */ fcm->data = MEM_dupallocN(fcm->data); fcm->curve = NULL; /* only do specific constraints if required */ if (fmi && fmi->copy_data) { fmi->copy_data(fcm, srcfcm); } } }
bContextStore *CTX_store_add(ListBase *contexts, const char *name, PointerRNA *ptr) { bContextStoreEntry *entry; bContextStore *ctx, *lastctx; /* ensure we have a context to put the entry in, if it was already used * we have to copy the context to ensure */ ctx= contexts->last; if(!ctx || ctx->used) { if(ctx) { lastctx= ctx; ctx= MEM_dupallocN(lastctx); BLI_duplicatelist(&ctx->entries, &lastctx->entries); } else ctx= MEM_callocN(sizeof(bContextStore), "bContextStore"); BLI_addtail(contexts, ctx); } entry= MEM_callocN(sizeof(bContextStoreEntry), "bContextStoreEntry"); BLI_strncpy(entry->name, name, sizeof(entry->name)); entry->ptr= *ptr; BLI_addtail(&ctx->entries, entry); return ctx; }
void screen_data_copy(bScreen *to, bScreen *from) { ScrVert *s1, *s2; ScrEdge *se; ScrArea *sa, *saf; /* free contents of 'to', is from blenkernel screen.c */ BKE_screen_free(to); to->flag = from->flag; BLI_duplicatelist(&to->vertbase, &from->vertbase); BLI_duplicatelist(&to->edgebase, &from->edgebase); BLI_duplicatelist(&to->areabase, &from->areabase); BLI_listbase_clear(&to->regionbase); s2 = to->vertbase.first; for (s1 = from->vertbase.first; s1; s1 = s1->next, s2 = s2->next) { s1->newv = s2; } for (se = to->edgebase.first; se; se = se->next) { se->v1 = se->v1->newv; se->v2 = se->v2->newv; BKE_screen_sort_scrvert(&(se->v1), &(se->v2)); } saf = from->areabase.first; for (sa = to->areabase.first; sa; sa = sa->next, saf = saf->next) { sa->v1 = sa->v1->newv; sa->v2 = sa->v2->newv; sa->v3 = sa->v3->newv; sa->v4 = sa->v4->newv; BLI_listbase_clear(&sa->spacedata); BLI_listbase_clear(&sa->regionbase); BLI_listbase_clear(&sa->actionzones); BLI_listbase_clear(&sa->handlers); ED_area_data_copy(sa, saf, true); } /* put at zero (needed?) */ for (s1 = from->vertbase.first; s1; s1 = s1->next) { s1->newv = NULL; } }
/* dst should be freed already, makes entire duplicate */ void copy_pose (bPose **dst, bPose *src, int copycon) { bPose *outPose; bPoseChannel *pchan; ListBase listb; if (!src) { *dst=NULL; return; } if (*dst==src) { printf("copy_pose source and target are the same\n"); *dst=NULL; return; } outPose= MEM_callocN(sizeof(bPose), "pose"); BLI_duplicatelist(&outPose->chanbase, &src->chanbase); outPose->iksolver = src->iksolver; outPose->ikdata = NULL; outPose->ikparam = MEM_dupallocN(src->ikparam); for (pchan=outPose->chanbase.first; pchan; pchan=pchan->next) { // TODO: rename this argument... if (copycon) { copy_constraints(&listb, &pchan->constraints, TRUE); // copy_constraints NULLs listb pchan->constraints= listb; pchan->path= NULL; // XXX remove this line when the new motionpaths are ready... (depreceated code) pchan->mpath= NULL; /* motion paths should not get copied yet... */ } if(pchan->prop) { pchan->prop= IDP_CopyProperty(pchan->prop); } } /* for now, duplicate Bone Groups too when doing this */ if (copycon) BLI_duplicatelist(&outPose->agroups, &src->agroups); *dst=outPose; }
Group *copy_group(Group *group) { Group *groupn; groupn= MEM_dupallocN(group); BLI_duplicatelist(&groupn->gobject, &group->gobject); return groupn; }
bContextStore *CTX_store_copy(bContextStore *store) { bContextStore *ctx; ctx= MEM_dupallocN(store); BLI_duplicatelist(&ctx->entries, &store->entries); return ctx; }
bAction *BKE_action_copy(Main *bmain, bAction *src) { bAction *dst = NULL; bActionGroup *dgrp, *sgrp; FCurve *dfcu, *sfcu; if (src == NULL) return NULL; dst = BKE_libblock_copy(bmain, &src->id); /* duplicate the lists of groups and markers */ BLI_duplicatelist(&dst->groups, &src->groups); BLI_duplicatelist(&dst->markers, &src->markers); /* copy F-Curves, fixing up the links as we go */ BLI_listbase_clear(&dst->curves); for (sfcu = src->curves.first; sfcu; sfcu = sfcu->next) { /* duplicate F-Curve */ dfcu = copy_fcurve(sfcu); BLI_addtail(&dst->curves, dfcu); /* fix group links (kindof bad list-in-list search, but this is the most reliable way) */ for (dgrp = dst->groups.first, sgrp = src->groups.first; dgrp && sgrp; dgrp = dgrp->next, sgrp = sgrp->next) { if (sfcu->grp == sgrp) { dfcu->grp = dgrp; if (dgrp->channels.first == sfcu) dgrp->channels.first = dfcu; if (dgrp->channels.last == sfcu) dgrp->channels.last = dfcu; break; } } } BKE_id_copy_ensure_local(bmain, &src->id, &dst->id); return dst; }
/* dst should be freed already, makes entire duplicate */ void BKE_pose_copy_data(bPose **dst, bPose *src, int copycon) { bPose *outPose; bPoseChannel *pchan; ListBase listb; if (!src) { *dst = NULL; return; } outPose = MEM_callocN(sizeof(bPose), "pose"); BLI_duplicatelist(&outPose->chanbase, &src->chanbase); outPose->iksolver = src->iksolver; outPose->ikdata = NULL; outPose->ikparam = MEM_dupallocN(src->ikparam); outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { /* TODO: rename this argument... */ if (copycon) { BKE_copy_constraints(&listb, &pchan->constraints, TRUE); // BKE_copy_constraints NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } if (pchan->prop) { pchan->prop = IDP_CopyProperty(pchan->prop); } } /* for now, duplicate Bone Groups too when doing this */ if (copycon) BLI_duplicatelist(&outPose->agroups, &src->agroups); *dst = outPose; }
BoidSettings *boid_copy_settings(BoidSettings *boids) { BoidSettings *nboids = NULL; if (boids) { BoidState *state; BoidState *nstate; nboids = MEM_dupallocN(boids); BLI_duplicatelist(&nboids->states, &boids->states); state = boids->states.first; nstate = nboids->states.first; for (; state; state=state->next, nstate=nstate->next) { BLI_duplicatelist(&nstate->rules, &state->rules); BLI_duplicatelist(&nstate->conditions, &state->conditions); BLI_duplicatelist(&nstate->actions, &state->actions); } } return nboids; }
ListBase *folderlist_duplicate(ListBase* folderlist) { if (folderlist) { ListBase *folderlistn= MEM_callocN(sizeof(ListBase), "copy folderlist"); FolderList *folder; BLI_duplicatelist(folderlistn, folderlist); for (folder= folderlistn->first; folder; folder= folder->next) { folder->foldername= MEM_dupallocN(folder->foldername); } return folderlistn; } return NULL; }
/** * Duplicate a workspace including its layouts. Does not activate the workspace, but * it stores the screen-layout to be activated (BKE_workspace_temp_layout_store) */ WorkSpace *ED_workspace_duplicate(WorkSpace *workspace_old, Main *bmain, wmWindow *win) { WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook); ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old); WorkSpace *workspace_new = ED_workspace_add(bmain, workspace_old->id.name + 2); workspace_new->flags = workspace_old->flags; BLI_duplicatelist(&workspace_new->owner_ids, &workspace_old->owner_ids); /* TODO(campbell): tools */ for (WorkSpaceLayout *layout_old = layouts_old->first; layout_old; layout_old = layout_old->next) { WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate( bmain, workspace_new, layout_old, win); if (layout_active_old == layout_old) { win->workspace_hook->temp_layout_store = layout_new; } } return workspace_new; }
MetaBall *BKE_mball_copy(MetaBall *mb) { MetaBall *mbn; int a; mbn = BKE_libblock_copy(&mb->id); BLI_duplicatelist(&mbn->elems, &mb->elems); mbn->mat = MEM_dupallocN(mb->mat); for (a = 0; a < mbn->totcol; a++) { id_us_plus((ID *)mbn->mat[a]); } mbn->editelems = NULL; mbn->lastelem = NULL; if (mb->id.lib) { BKE_id_lib_local_paths(G.main, mb->id.lib, &mbn->id); } return mbn; }
static void layer_collections_copy_data(ViewLayer *view_layer_dst, const ViewLayer *view_layer_src, ListBase *layer_collections_dst, const ListBase *layer_collections_src) { BLI_duplicatelist(layer_collections_dst, layer_collections_src); LayerCollection *layer_collection_dst = layer_collections_dst->first; const LayerCollection *layer_collection_src = layer_collections_src->first; while (layer_collection_dst != NULL) { layer_collections_copy_data(view_layer_dst, view_layer_src, &layer_collection_dst->layer_collections, &layer_collection_src->layer_collections); if (layer_collection_src == view_layer_src->active_collection) { view_layer_dst->active_collection = layer_collection_dst; } layer_collection_dst = layer_collection_dst->next; layer_collection_src = layer_collection_src->next; } }
/** * Move here pose function for game engine so that we can mix with GE objects * Principle is as follow: * Use Blender structures so that BKE_pose_where_is can be used unchanged * Copy the constraint so that they can be enabled/disabled/added/removed at runtime * Don't copy the constraints for the pose used by the Action actuator, it does not need them. * Scan the constraint structures so that the KX equivalent of target objects are identified and * stored in separate list. * When it is about to evaluate the pose, set the KX object position in the obmat of the corresponding * Blender objects and restore after the evaluation. */ static void game_copy_pose(bPose **dst, bPose *src, int copy_constraint) { bPose *out; bPoseChannel *pchan, *outpchan; GHash *ghash; /* the game engine copies the current armature pose and then swaps * the object pose pointer. this makes it possible to change poses * without affecting the original blender data. */ if (!src) { *dst=NULL; return; } else if (*dst==src) { printf("game_copy_pose source and target are the same\n"); *dst=NULL; return; } out= (bPose*)MEM_dupallocN(src); out->chanhash = NULL; out->agroups.first= out->agroups.last= NULL; out->ikdata = NULL; out->ikparam = MEM_dupallocN(src->ikparam); out->flag |= POSE_GAME_ENGINE; BLI_duplicatelist(&out->chanbase, &src->chanbase); /* remap pointers */ ghash= BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "game_copy_pose gh"); pchan= (bPoseChannel *)src->chanbase.first; outpchan= (bPoseChannel *)out->chanbase.first; for (; pchan; pchan=pchan->next, outpchan=outpchan->next) BLI_ghash_insert(ghash, pchan, outpchan); for (pchan = (bPoseChannel *)out->chanbase.first; pchan; pchan = pchan->next) { pchan->parent= (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->parent); pchan->child= (bPoseChannel *)BLI_ghash_lookup(ghash, pchan->child); if (copy_constraint) { ListBase listb; // copy all constraint for backward compatibility // BKE_constraints_copy NULLs listb, no need to make extern for this operation. BKE_constraints_copy(&listb, &pchan->constraints, false); pchan->constraints= listb; } else { BLI_listbase_clear(&pchan->constraints); } if (pchan->custom) { id_us_plus(&pchan->custom->id); } // fails to link, props are not used in the BGE yet. #if 0 if (pchan->prop) pchan->prop= IDP_CopyProperty(pchan->prop); #endif pchan->prop= NULL; } BLI_ghash_free(ghash, NULL, NULL); // set acceleration structure for channel lookup BKE_pose_channels_hash_make(out); *dst=out; }
/** * Allocate a new pose on the heap, and copy the src pose and it's channels * into the new pose. *dst is set to the newly allocated structure, and assumed to be NULL. * * \param dst Should be freed already, makes entire duplicate. */ void BKE_pose_copy_data(bPose **dst, bPose *src, const bool copy_constraints) { bPose *outPose; bPoseChannel *pchan; ListBase listb; if (!src) { *dst = NULL; return; } outPose = MEM_callocN(sizeof(bPose), "pose"); BLI_duplicatelist(&outPose->chanbase, &src->chanbase); /* Rebuild ghash here too, so that name lookups below won't be too bad... * BUT this will have the penalty that the ghash will be built twice * if BKE_pose_rebuild() gets called after this... */ if (outPose->chanbase.first != outPose->chanbase.last) { outPose->chanhash = NULL; BKE_pose_channels_hash_make(outPose); } outPose->iksolver = src->iksolver; outPose->ikdata = NULL; outPose->ikparam = MEM_dupallocN(src->ikparam); outPose->avs = src->avs; for (pchan = outPose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->custom) { id_us_plus(&pchan->custom->id); } /* warning, O(n2) here, if done without the hash, but these are rarely used features. */ if (pchan->custom_tx) { pchan->custom_tx = BKE_pose_channel_find_name(outPose, pchan->custom_tx->name); } if (pchan->bbone_prev) { pchan->bbone_prev = BKE_pose_channel_find_name(outPose, pchan->bbone_prev->name); } if (pchan->bbone_next) { pchan->bbone_next = BKE_pose_channel_find_name(outPose, pchan->bbone_next->name); } if (copy_constraints) { BKE_constraints_copy(&listb, &pchan->constraints, true); // BKE_constraints_copy NULLs listb pchan->constraints = listb; pchan->mpath = NULL; /* motion paths should not get copied yet... */ } if (pchan->prop) { pchan->prop = IDP_CopyProperty(pchan->prop); } } /* for now, duplicate Bone Groups too when doing this */ if (copy_constraints) { BLI_duplicatelist(&outPose->agroups, &src->agroups); } *dst = outPose; }
/* position block relative to but, result is in window space */ static void ui_popup_block_position(wmWindow *window, ARegion *butregion, uiBut *but, uiBlock *block) { uiPopupBlockHandle *handle = block->handle; /* Compute button position in window coordinates using the source * button region/block, to position the popup attached to it. */ rctf butrct; if (!handle->refresh) { ui_block_to_window_rctf(butregion, but->block, &butrct, &but->rect); /* widget_roundbox_set has this correction too, keep in sync */ if (but->type != UI_BTYPE_PULLDOWN) { if (but->drawflag & UI_BUT_ALIGN_TOP) { butrct.ymax += U.pixelsize; } if (but->drawflag & UI_BUT_ALIGN_LEFT) { butrct.xmin -= U.pixelsize; } } handle->prev_butrct = butrct; } else { /* For refreshes, keep same button position so popup doesn't move. */ butrct = handle->prev_butrct; } /* Compute block size in window space, based on buttons contained in it. */ if (block->rect.xmin == 0.0f && block->rect.xmax == 0.0f) { if (block->buttons.first) { BLI_rctf_init_minmax(&block->rect); for (uiBut *bt = block->buttons.first; bt; bt = bt->next) { if (block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT) { bt->rect.xmax += UI_MENU_SUBMENU_PADDING; } BLI_rctf_union(&block->rect, &bt->rect); } } else { /* we're nice and allow empty blocks too */ block->rect.xmin = block->rect.ymin = 0; block->rect.xmax = block->rect.ymax = 20; } } ui_block_to_window_rctf(butregion, but->block, &block->rect, &block->rect); /* Compute direction relative to button, based on available space. */ const int size_x = BLI_rctf_size_x(&block->rect) + 0.2f * UI_UNIT_X; /* 4 for shadow */ const int size_y = BLI_rctf_size_y(&block->rect) + 0.2f * UI_UNIT_Y; const int center_x = (block->direction & UI_DIR_CENTER_X) ? size_x / 2 : 0; const int center_y = (block->direction & UI_DIR_CENTER_Y) ? size_y / 2 : 0; short dir1 = 0, dir2 = 0; if (!handle->refresh) { bool left = 0, right = 0, top = 0, down = 0; const int win_x = WM_window_pixels_x(window); const int win_y = WM_window_pixels_y(window); /* Take into account maximum size so we don't have to flip on refresh. */ const float max_size_x = max_ff(size_x, handle->max_size_x); const float max_size_y = max_ff(size_y, handle->max_size_y); /* check if there's space at all */ if (butrct.xmin - max_size_x + center_x > 0.0f) { left = 1; } if (butrct.xmax + max_size_x - center_x < win_x) { right = 1; } if (butrct.ymin - max_size_y + center_y > 0.0f) { down = 1; } if (butrct.ymax + max_size_y - center_y < win_y) { top = 1; } if (top == 0 && down == 0) { if (butrct.ymin - max_size_y < win_y - butrct.ymax - max_size_y) { top = 1; } else { down = 1; } } dir1 = (block->direction & UI_DIR_ALL); /* Secondary directions. */ if (dir1 & (UI_DIR_UP | UI_DIR_DOWN)) { if (dir1 & UI_DIR_LEFT) { dir2 = UI_DIR_LEFT; } else if (dir1 & UI_DIR_RIGHT) { dir2 = UI_DIR_RIGHT; } dir1 &= (UI_DIR_UP | UI_DIR_DOWN); } if ((dir2 == 0) && (dir1 == UI_DIR_LEFT || dir1 == UI_DIR_RIGHT)) { dir2 = UI_DIR_DOWN; } if ((dir2 == 0) && (dir1 == UI_DIR_UP || dir1 == UI_DIR_DOWN)) { dir2 = UI_DIR_LEFT; } /* no space at all? don't change */ if (left || right) { if (dir1 == UI_DIR_LEFT && left == 0) { dir1 = UI_DIR_RIGHT; } if (dir1 == UI_DIR_RIGHT && right == 0) { dir1 = UI_DIR_LEFT; } /* this is aligning, not append! */ if (dir2 == UI_DIR_LEFT && right == 0) { dir2 = UI_DIR_RIGHT; } if (dir2 == UI_DIR_RIGHT && left == 0) { dir2 = UI_DIR_LEFT; } } if (down || top) { if (dir1 == UI_DIR_UP && top == 0) { dir1 = UI_DIR_DOWN; } if (dir1 == UI_DIR_DOWN && down == 0) { dir1 = UI_DIR_UP; } BLI_assert(dir2 != UI_DIR_UP); // if (dir2 == UI_DIR_UP && top == 0) { dir2 = UI_DIR_DOWN; } if (dir2 == UI_DIR_DOWN && down == 0) { dir2 = UI_DIR_UP; } } handle->prev_dir1 = dir1; handle->prev_dir2 = dir2; } else { /* For refreshes, keep same popup direct so popup doesn't move * to a totally different position while editing in it. */ dir1 = handle->prev_dir1; dir2 = handle->prev_dir2; } /* Compute offset based on direction. */ float offset_x = 0, offset_y = 0; /* Ensure buttons don't come between the parent button and the popup, see: T63566. */ const float offset_overlap = max_ff(U.pixelsize, 1.0f); if (dir1 == UI_DIR_LEFT) { offset_x = (butrct.xmin - block->rect.xmax) + offset_overlap; if (dir2 == UI_DIR_UP) { offset_y = butrct.ymin - block->rect.ymin - center_y - UI_MENU_PADDING; } else { offset_y = butrct.ymax - block->rect.ymax + center_y + UI_MENU_PADDING; } } else if (dir1 == UI_DIR_RIGHT) { offset_x = (butrct.xmax - block->rect.xmin) - offset_overlap; if (dir2 == UI_DIR_UP) { offset_y = butrct.ymin - block->rect.ymin - center_y - UI_MENU_PADDING; } else { offset_y = butrct.ymax - block->rect.ymax + center_y + UI_MENU_PADDING; } } else if (dir1 == UI_DIR_UP) { offset_y = (butrct.ymax - block->rect.ymin) - offset_overlap; if (dir2 == UI_DIR_RIGHT) { offset_x = butrct.xmax - block->rect.xmax + center_x; } else { offset_x = butrct.xmin - block->rect.xmin - center_x; } /* changed direction? */ if ((dir1 & block->direction) == 0) { /* TODO: still do */ UI_block_order_flip(block); } } else if (dir1 == UI_DIR_DOWN) { offset_y = (butrct.ymin - block->rect.ymax) + offset_overlap; if (dir2 == UI_DIR_RIGHT) { offset_x = butrct.xmax - block->rect.xmax + center_x; } else { offset_x = butrct.xmin - block->rect.xmin - center_x; } /* changed direction? */ if ((dir1 & block->direction) == 0) { /* TODO: still do */ UI_block_order_flip(block); } } /* Center over popovers for eg. */ if (block->direction & UI_DIR_CENTER_X) { offset_x += BLI_rctf_size_x(&butrct) / ((dir2 == UI_DIR_LEFT) ? 2 : -2); } /* Apply offset, buttons in window coords. */ for (uiBut *bt = block->buttons.first; bt; bt = bt->next) { ui_block_to_window_rctf(butregion, but->block, &bt->rect, &bt->rect); BLI_rctf_translate(&bt->rect, offset_x, offset_y); /* ui_but_update recalculates drawstring size in pixels */ ui_but_update(bt); } BLI_rctf_translate(&block->rect, offset_x, offset_y); /* Safety calculus. */ { const float midx = BLI_rctf_cent_x(&butrct); const float midy = BLI_rctf_cent_y(&butrct); /* when you are outside parent button, safety there should be smaller */ /* parent button to left */ if (midx < block->rect.xmin) { block->safety.xmin = block->rect.xmin - 3; } else { block->safety.xmin = block->rect.xmin - 40; } /* parent button to right */ if (midx > block->rect.xmax) { block->safety.xmax = block->rect.xmax + 3; } else { block->safety.xmax = block->rect.xmax + 40; } /* parent button on bottom */ if (midy < block->rect.ymin) { block->safety.ymin = block->rect.ymin - 3; } else { block->safety.ymin = block->rect.ymin - 40; } /* parent button on top */ if (midy > block->rect.ymax) { block->safety.ymax = block->rect.ymax + 3; } else { block->safety.ymax = block->rect.ymax + 40; } /* exception for switched pulldowns... */ if (dir1 && (dir1 & block->direction) == 0) { if (dir2 == UI_DIR_RIGHT) { block->safety.xmax = block->rect.xmax + 3; } if (dir2 == UI_DIR_LEFT) { block->safety.xmin = block->rect.xmin - 3; } } block->direction = dir1; } /* keep a list of these, needed for pulldown menus */ uiSafetyRct *saferct = MEM_callocN(sizeof(uiSafetyRct), "uiSafetyRct"); saferct->parent = butrct; saferct->safety = block->safety; BLI_freelistN(&block->saferct); BLI_duplicatelist(&block->saferct, &but->block->saferct); BLI_addhead(&block->saferct, saferct); }
Scene *BKE_scene_copy(Scene *sce, int type) { Scene *scen; ToolSettings *ts; Base *base, *obase; if (type == SCE_COPY_EMPTY) { ListBase lb; /* XXX. main should become an arg */ scen = BKE_scene_add(G.main, sce->id.name + 2); lb = scen->r.layers; scen->r = sce->r; scen->r.layers = lb; scen->unit = sce->unit; scen->physics_settings = sce->physics_settings; scen->gm = sce->gm; scen->audio = sce->audio; MEM_freeN(scen->toolsettings); } else { scen = BKE_libblock_copy(&sce->id); BLI_duplicatelist(&(scen->base), &(sce->base)); clear_id_newpoins(); id_us_plus((ID *)scen->world); id_us_plus((ID *)scen->set); id_us_plus((ID *)scen->gm.dome.warptext); scen->ed = NULL; scen->theDag = NULL; scen->obedit = NULL; scen->stats = NULL; scen->fps_info = NULL; BLI_duplicatelist(&(scen->markers), &(sce->markers)); BLI_duplicatelist(&(scen->transform_spaces), &(sce->transform_spaces)); BLI_duplicatelist(&(scen->r.layers), &(sce->r.layers)); BKE_keyingsets_copy(&(scen->keyingsets), &(sce->keyingsets)); if (sce->nodetree) { /* ID's are managed on both copy and switch */ scen->nodetree = ntreeCopyTree(sce->nodetree); ntreeSwitchID(scen->nodetree, &sce->id, &scen->id); } obase = sce->base.first; base = scen->base.first; while (base) { id_us_plus(&base->object->id); if (obase == sce->basact) scen->basact = base; obase = obase->next; base = base->next; } /* copy color management settings */ BKE_color_managed_display_settings_copy(&scen->display_settings, &sce->display_settings); BKE_color_managed_view_settings_copy(&scen->view_settings, &sce->view_settings); BKE_color_managed_view_settings_copy(&scen->r.im_format.view_settings, &sce->r.im_format.view_settings); BLI_strncpy(scen->sequencer_colorspace_settings.name, sce->sequencer_colorspace_settings.name, sizeof(scen->sequencer_colorspace_settings.name)); /* remove animation used by sequencer */ if (type != SCE_COPY_FULL) remove_sequencer_fcurves(scen); } /* tool settings */ scen->toolsettings = MEM_dupallocN(sce->toolsettings); ts = scen->toolsettings; if (ts) { if (ts->vpaint) { ts->vpaint = MEM_dupallocN(ts->vpaint); ts->vpaint->paintcursor = NULL; ts->vpaint->vpaint_prev = NULL; ts->vpaint->wpaint_prev = NULL; BKE_paint_copy(&ts->vpaint->paint, &ts->vpaint->paint); } if (ts->wpaint) { ts->wpaint = MEM_dupallocN(ts->wpaint); ts->wpaint->paintcursor = NULL; ts->wpaint->vpaint_prev = NULL; ts->wpaint->wpaint_prev = NULL; BKE_paint_copy(&ts->wpaint->paint, &ts->wpaint->paint); } if (ts->sculpt) { ts->sculpt = MEM_dupallocN(ts->sculpt); BKE_paint_copy(&ts->sculpt->paint, &ts->sculpt->paint); } BKE_paint_copy(&ts->imapaint.paint, &ts->imapaint.paint); ts->imapaint.paintcursor = NULL; ts->particle.paintcursor = NULL; } /* make a private copy of the avicodecdata */ if (sce->r.avicodecdata) { scen->r.avicodecdata = MEM_dupallocN(sce->r.avicodecdata); scen->r.avicodecdata->lpFormat = MEM_dupallocN(scen->r.avicodecdata->lpFormat); scen->r.avicodecdata->lpParms = MEM_dupallocN(scen->r.avicodecdata->lpParms); } /* make a private copy of the qtcodecdata */ if (sce->r.qtcodecdata) { scen->r.qtcodecdata = MEM_dupallocN(sce->r.qtcodecdata); scen->r.qtcodecdata->cdParms = MEM_dupallocN(scen->r.qtcodecdata->cdParms); } if (sce->r.ffcodecdata.properties) { /* intentionally check scen not sce. */ scen->r.ffcodecdata.properties = IDP_CopyProperty(sce->r.ffcodecdata.properties); } /* NOTE: part of SCE_COPY_LINK_DATA and SCE_COPY_FULL operations * are done outside of blenkernel with ED_objects_single_users! */ /* camera */ if (type == SCE_COPY_LINK_DATA || type == SCE_COPY_FULL) { ID_NEW(scen->camera); } /* before scene copy */ sound_create_scene(scen); /* world */ if (type == SCE_COPY_FULL) { BKE_copy_animdata_id_action((ID *)scen); if (scen->world) { id_us_plus((ID *)scen->world); scen->world = BKE_world_copy(scen->world); BKE_copy_animdata_id_action((ID *)scen->world); } if (sce->ed) { scen->ed = MEM_callocN(sizeof(Editing), "addseq"); scen->ed->seqbasep = &scen->ed->seqbase; BKE_sequence_base_dupli_recursive(sce, scen, &scen->ed->seqbase, &sce->ed->seqbase, SEQ_DUPE_ALL); } } return scen; }