static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves, short select) { SpaceNode *snode = CTX_wm_space_node(C); bNode *node; ARegion *ar = CTX_wm_region(C); rcti rect; bool changed = false; /* get rectangle from operator */ BLI_lasso_boundbox(&rect, mcords, moves); /* do actual selection */ for (node = snode->edittree->nodes.first; node; node = node->next) { int screen_co[2]; const float cent[2] = {BLI_rctf_cent_x(&node->totr), BLI_rctf_cent_y(&node->totr)}; /* marker in screen coords */ if (UI_view2d_view_to_region_clip(&ar->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) && BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { nodeSetSelected(node, select); changed = true; } } if (changed) { WM_event_add_notifier(C, NC_NODE | NA_SELECTED, NULL); } return changed; }
void BLI_rctf_resize(rctf *rect, float x, float y) { rect->xmin = rect->xmax = BLI_rctf_cent_x(rect); rect->ymin = rect->ymax = BLI_rctf_cent_y(rect); rect->xmin -= x * 0.5f; rect->ymin -= y * 0.5f; rect->xmax = rect->xmin + x; rect->ymax = rect->ymin + y; }
void BLI_rctf_scale(rctf *rect, const float scale) { const float cent_x = BLI_rctf_cent_x(rect); const float cent_y = BLI_rctf_cent_y(rect); const float size_x_half = BLI_rctf_size_x(rect) * (scale * 0.5f); const float size_y_half = BLI_rctf_size_y(rect) * (scale * 0.5f); rect->xmin = cent_x - size_x_half; rect->ymin = cent_y - size_y_half; rect->xmax = cent_x + size_x_half; rect->ymax = cent_y + size_y_half; }
/** * Expand the rectangle to fit a rotated \a src. */ void BLI_rctf_rotate_expand(rctf *dst, const rctf *src, const float angle) { const float mat2[2] = {sinf(angle), cosf(angle)}; const float cent[2] = {BLI_rctf_cent_x(src), BLI_rctf_cent_y(src)}; float corner[2], corner_rot[2], corder_max[2]; /* x is same for both corners */ corner[0] = src->xmax - cent[0]; corner[1] = src->ymax - cent[1]; ROTATE_SINCOS(corner_rot, mat2, corner); corder_max[0] = fabsf(corner_rot[0]); corder_max[1] = fabsf(corner_rot[1]); corner[1] *= -1; ROTATE_SINCOS(corner_rot, mat2, corner); corder_max[0] = MAX2(corder_max[0], fabsf(corner_rot[0])); corder_max[1] = MAX2(corder_max[1], fabsf(corner_rot[1])); dst->xmin = cent[0] - corder_max[0]; dst->xmax = cent[0] + corder_max[0]; dst->ymin = cent[1] - corder_max[1]; dst->ymax = cent[1] + corder_max[1]; }
/* 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); }
void BLI_rctf_recenter(rctf *rect, float x, float y) { const float dx = x - BLI_rctf_cent_x(rect); const float dy = y - BLI_rctf_cent_y(rect); BLI_rctf_translate(rect, dx, dy); }