diff options
-rw-r--r-- | source/blender/editors/screen/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_draw.c | 8 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_edit.c | 492 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_geometry.c | 462 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_intern.h | 24 | ||||
-rw-r--r-- | source/blender/editors/screen/screen_ops.c | 20 |
6 files changed, 536 insertions, 471 deletions
diff --git a/source/blender/editors/screen/CMakeLists.txt b/source/blender/editors/screen/CMakeLists.txt index ee114eba3c5..4be65f60b21 100644 --- a/source/blender/editors/screen/CMakeLists.txt +++ b/source/blender/editors/screen/CMakeLists.txt @@ -46,6 +46,7 @@ set(SRC screen_context.c screen_draw.c screen_edit.c + screen_geometry.c screen_ops.c screen_user_menu.c screendump.c diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index 0a693893310..b5b0d16f6a7 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -44,8 +44,8 @@ */ static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos) { - const float width = area_geometry_width(sa) - 1; - const float height = area_geometry_height(sa) - 1; + const float width = screen_geom_area_width(sa) - 1; + const float height = screen_geom_area_height(sa) - 1; vec2f points[10]; short i; float w, h; @@ -125,8 +125,8 @@ static void draw_horizontal_join_shape(ScrArea *sa, char dir, unsigned int pos) */ static void draw_vertical_join_shape(ScrArea *sa, char dir, unsigned int pos) { - const float width = area_geometry_width(sa) - 1; - const float height = area_geometry_height(sa) - 1; + const float width = screen_geom_area_width(sa) - 1; + const float height = screen_geom_area_height(sa) - 1; vec2f points[10]; short i; float w, h; diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index b3424ae3fb4..1b2908104f5 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -74,104 +74,6 @@ #include "screen_intern.h" /* own module include */ -/* ******************* screen vert, edge, area managing *********************** */ - -static ScrVert *screen_addvert_ex(ScrAreaMap *area_map, short x, short y) -{ - ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert"); - sv->vec.x = x; - sv->vec.y = y; - - BLI_addtail(&area_map->vertbase, sv); - return sv; -} -static ScrVert *screen_addvert(bScreen *sc, short x, short y) -{ - return screen_addvert_ex(AREAMAP_FROM_SCREEN(sc), x, y); -} - -static ScrEdge *screen_addedge_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2) -{ - ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge"); - - BKE_screen_sort_scrvert(&v1, &v2); - se->v1 = v1; - se->v2 = v2; - - BLI_addtail(&area_map->edgebase, se); - return se; -} -static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2) -{ - return screen_addedge_ex(AREAMAP_FROM_SCREEN(sc), v1, v2); -} - -bool scredge_is_horizontal(ScrEdge *se) -{ - return (se->v1->vec.y == se->v2->vec.y); -} - -/** - * \param bounds_rect: Either window or screen bounds. Used to exclude edges along window/screen edges. - */ -ScrEdge *screen_area_map_find_active_scredge( - const ScrAreaMap *area_map, - const rcti *bounds_rect, - const int mx, const int my) -{ - int safety = U.widget_unit / 10; - - CLAMP_MIN(safety, 2); - - for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) { - if (scredge_is_horizontal(se)) { - if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) { - short min, max; - min = MIN2(se->v1->vec.x, se->v2->vec.x); - max = MAX2(se->v1->vec.x, se->v2->vec.x); - - if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max) - return se; - } - } - else { - if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) { - short min, max; - min = MIN2(se->v1->vec.y, se->v2->vec.y); - max = MAX2(se->v1->vec.y, se->v2->vec.y); - - if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max) - return se; - } - } - } - - return NULL; -} - -/* need win size to make sure not to include edges along screen edge */ -ScrEdge *screen_find_active_scredge( - const wmWindow *win, const bScreen *screen, - const int mx, const int my) -{ - /* Use layout size (screen excluding global areas) for screen-layout area edges */ - rcti screen_rect; - ScrEdge *se; - - WM_window_screen_rect_calc(win, &screen_rect); - se = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my); - - if (!se) { - /* Use entire window size (screen including global areas) for global area edges */ - rcti win_rect; - WM_window_rect_calc(win, &win_rect); - se = screen_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my); - } - return se; -} - - - /* adds no space data */ static ScrArea *screen_addarea_ex( ScrAreaMap *area_map, @@ -210,68 +112,6 @@ static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa) MEM_freeN(sa); } -/* return 0: no split possible */ -/* else return (integer) screencoordinate split point */ -static short testsplitpoint(ScrArea *sa, const rcti *window_rect, char dir, float fac) -{ - short x, y; - const int cur_area_width = area_geometry_width(sa); - const int cur_area_height = area_geometry_height(sa); - const short area_min_x = AREAMINX; - const short area_min_y = ED_area_headersize(); - int area_min; - - // area big enough? - if (dir == 'v' && (cur_area_width <= 2 * area_min_x)) return 0; - if (dir == 'h' && (cur_area_height <= 2 * area_min_y)) return 0; - - // to be sure - CLAMP(fac, 0.0f, 1.0f); - - if (dir == 'h') { - y = sa->v1->vec.y + round_fl_to_short(fac * cur_area_height); - - area_min = area_min_y; - - if (sa->v1->vec.y > window_rect->ymin) { - area_min += U.pixelsize; - } - if (sa->v2->vec.y < (window_rect->ymax - 1)) { - area_min += U.pixelsize; - } - - if (y - sa->v1->vec.y < area_min) { - y = sa->v1->vec.y + area_min; - } - else if (sa->v2->vec.y - y < area_min) { - y = sa->v2->vec.y - area_min; - } - - return y; - } - else { - x = sa->v1->vec.x + round_fl_to_short(fac * cur_area_width); - - area_min = area_min_x; - - if (sa->v1->vec.x > window_rect->xmin) { - area_min += U.pixelsize; - } - if (sa->v4->vec.x < (window_rect->xmax - 1)) { - area_min += U.pixelsize; - } - - if (x - sa->v1->vec.x < area_min) { - x = sa->v1->vec.x + area_min; - } - else if (sa->v4->vec.x - x < area_min) { - x = sa->v4->vec.x - area_min; - } - - return x; - } -} - ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge) { ScrArea *newa = NULL; @@ -283,7 +123,7 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo WM_window_rect_calc(win, &window_rect); - split = testsplitpoint(sa, &window_rect, dir, fac); + split = screen_geom_find_area_split_point(sa, &window_rect, dir, fac); if (split == 0) return NULL; /* note regarding (fac > 0.5f) checks below. @@ -292,15 +132,15 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo if (dir == 'h') { /* new vertices */ - sv1 = screen_addvert(sc, sa->v1->vec.x, split); - sv2 = screen_addvert(sc, sa->v4->vec.x, split); + sv1 = screen_geom_vertex_add(sc, sa->v1->vec.x, split); + sv2 = screen_geom_vertex_add(sc, sa->v4->vec.x, split); /* new edges */ - screen_addedge(sc, sa->v1, sv1); - screen_addedge(sc, sv1, sa->v2); - screen_addedge(sc, sa->v3, sv2); - screen_addedge(sc, sv2, sa->v4); - screen_addedge(sc, sv1, sv2); + screen_geom_edge_add(sc, sa->v1, sv1); + screen_geom_edge_add(sc, sv1, sa->v2); + screen_geom_edge_add(sc, sa->v3, sv2); + screen_geom_edge_add(sc, sv2, sa->v4); + screen_geom_edge_add(sc, sv1, sv2); if (fac > 0.5f) { /* new areas: top */ @@ -324,15 +164,15 @@ ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, flo } else { /* new vertices */ - sv1 = screen_addvert(sc, split, sa->v1->vec.y); - sv2 = screen_addvert(sc, split, sa->v2->vec.y); + sv1 = screen_geom_vertex_add(sc, split, sa->v1->vec.y); + sv2 = screen_geom_vertex_add(sc, split, sa->v2->vec.y); /* new edges */ - screen_addedge(sc, sa->v1, sv1); - screen_addedge(sc, sv1, sa->v4); - screen_addedge(sc, sa->v2, sv2); - screen_addedge(sc, sv2, sa->v3); - screen_addedge(sc, sv1, sv2); + screen_geom_edge_add(sc, sa->v1, sv1); + screen_geom_edge_add(sc, sv1, sa->v4); + screen_geom_edge_add(sc, sa->v2, sv2); + screen_geom_edge_add(sc, sv2, sa->v3); + screen_geom_edge_add(sc, sv1, sv2); if (fac > 0.5f) { /* new areas: right */ @@ -375,15 +215,15 @@ bScreen *screen_add(Main *bmain, const char *name, const rcti *rect) sc->do_refresh = true; sc->redraws_flag = TIME_ALL_3D_WIN | TIME_ALL_ANIM_WIN; - sv1 = screen_addvert(sc, rect->xmin, rect->ymin); - sv2 = screen_addvert(sc, rect->xmin, rect->ymax - 1); - sv3 = screen_addvert(sc, rect->xmax - 1, rect->ymax - 1); - sv4 = screen_addvert(sc, rect->xmax - 1, rect->ymin); + sv1 = screen_geom_vertex_add(sc, rect->xmin, rect->ymin); + sv2 = screen_geom_vertex_add(sc, rect->xmin, rect->ymax - 1); + sv3 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymax - 1); + sv4 = screen_geom_vertex_add(sc, rect->xmax - 1, rect->ymin); - screen_addedge(sc, sv1, sv2); - screen_addedge(sc, sv2, sv3); - screen_addedge(sc, sv3, sv4); - screen_addedge(sc, sv4, sv1); + screen_geom_edge_add(sc, sv1, sv2); + screen_geom_edge_add(sc, sv2, sv3); + screen_geom_edge_add(sc, sv3, sv4); + screen_geom_edge_add(sc, sv4, sv1); /* dummy type, no spacedata */ screen_addarea(sc, sv1, sv2, sv3, sv4, SPACE_EMPTY); @@ -447,15 +287,6 @@ void screen_new_activate_prepare(const wmWindow *win, bScreen *screen_new) } -int area_geometry_height(const ScrArea *area) -{ - return area->v2->vec.y - area->v1->vec.y + 1; -} -int area_geometry_width(const ScrArea *area) -{ - return area->v4->vec.x - area->v1->vec.x + 1; -} - /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */ /* -1 = not valid check */ /* used with join operator */ @@ -508,26 +339,26 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) if (dir == 0) { sa1->v1 = sa2->v1; sa1->v2 = sa2->v2; - screen_addedge(scr, sa1->v2, sa1->v3); - screen_addedge(scr, sa1->v1, sa1->v4); + screen_geom_edge_add(scr, sa1->v2, sa1->v3); + screen_geom_edge_add(scr, sa1->v1, sa1->v4); } else if (dir == 1) { sa1->v2 = sa2->v2; sa1->v3 = sa2->v3; - screen_addedge(scr, sa1->v1, sa1->v2); - screen_addedge(scr, sa1->v3, sa1->v4); + screen_geom_edge_add(scr, sa1->v1, sa1->v2); + screen_geom_edge_add(scr, sa1->v3, sa1->v4); } else if (dir == 2) { sa1->v3 = sa2->v3; sa1->v4 = sa2->v4; - screen_addedge(scr, sa1->v2, sa1->v3); - screen_addedge(scr, sa1->v1, sa1->v4); + screen_geom_edge_add(scr, sa1->v2, sa1->v3); + screen_geom_edge_add(scr, sa1->v1, sa1->v4); } else if (dir == 3) { sa1->v1 = sa2->v1; sa1->v4 = sa2->v4; - screen_addedge(scr, sa1->v1, sa1->v2); - screen_addedge(scr, sa1->v3, sa1->v4); + screen_geom_edge_add(scr, sa1->v1, sa1->v2); + screen_geom_edge_add(scr, sa1->v3, sa1->v4); } screen_delarea(C, scr, sa2); @@ -538,243 +369,6 @@ int screen_area_join(bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2) return 1; } -void select_connected_scredge(const wmWindow *win, ScrEdge *edge) -{ - bScreen *sc = WM_window_get_active_screen(win); - ScrEdge *se; - int oneselected; - char dir; - - /* select connected, only in the right direction */ - /* 'dir' is the direction of EDGE */ - - if (edge->v1->vec.x == edge->v2->vec.x) dir = 'v'; - else dir = 'h'; - - ED_screen_verts_iter(win, sc, sv) { - sv->flag = 0; - } - - edge->v1->flag = 1; - edge->v2->flag = 1; - - oneselected = 1; - while (oneselected) { - se = sc->edgebase.first; - oneselected = 0; - while (se) { - if (se->v1->flag + se->v2->flag == 1) { - if (dir == 'h') { - if (se->v1->vec.y == se->v2->vec.y) { - se->v1->flag = se->v2->flag = 1; - oneselected = 1; - } - } - if (dir == 'v') { - if (se->v1->vec.x == se->v2->vec.x) { - se->v1->flag = se->v2->flag = 1; - oneselected = 1; - } - } - } - se = se->next; - } - } -} - -/** - * Test if screen vertices should be scaled and do if needed. - */ -static void screen_vertices_scale( - const wmWindow *win, bScreen *sc, - const rcti *window_rect, const rcti *screen_rect) -{ - /* clamp Y size of header sized areas when expanding windows - * avoids annoying empty space around file menu */ -#define USE_HEADER_SIZE_CLAMP - - const int headery_init = ED_area_headersize(); - const int screen_size_x = BLI_rcti_size_x(screen_rect); - const int screen_size_y = BLI_rcti_size_y(screen_rect); - ScrVert *sv = NULL; - ScrArea *sa; - int screen_size_x_prev, screen_size_y_prev; - float min[2], max[2]; - - /* calculate size */ - min[0] = min[1] = 20000.0f; - max[0] = max[1] = 0.0f; - - for (sv = sc->vertbase.first; sv; sv = sv->next) { - const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y}; - minmax_v2v2_v2(min, max, fv); - } - - screen_size_x_prev = (max[0] - min[0]) + 1; - screen_size_y_prev = (max[1] - min[1]) + 1; - - -#ifdef USE_HEADER_SIZE_CLAMP -#define TEMP_BOTTOM 1 -#define TEMP_TOP 2 - - /* if the window's Y axis grows, clamp header sized areas */ - if (screen_size_y_prev < screen_size_y) { /* growing? */ - const int headery_margin_max = headery_init + 5; - for (sa = sc->areabase.first; sa; sa = sa->next) { - ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); - sa->temp = 0; - - if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) { - if (sa->v2->vec.y == max[1]) { - if (area_geometry_height(sa) < headery_margin_max) { - sa->temp = TEMP_TOP; - } - } - else if (sa->v1->vec.y == min[1]) { - if (area_geometry_height(sa) < headery_margin_max) { - sa->temp = TEMP_BOTTOM; - } - } - } - } - } -#endif - - - if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) { - const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1); - const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1); - - /* make sure it fits! */ - for (sv = sc->vertbase.first; sv; sv = sv->next) { - sv->vec.x = screen_rect->xmin + round_fl_to_short((sv->vec.x - min[0]) * facx); - CLAMP(sv->vec.x, screen_rect->xmin, screen_rect->xmax - 1); - - sv->vec.y = screen_rect->ymin + round_fl_to_short((sv->vec.y - min[1]) * facy); - CLAMP(sv->vec.y, screen_rect->ymin, screen_rect->ymax - 1); - } - } - - -#ifdef USE_HEADER_SIZE_CLAMP - if (screen_size_y_prev < screen_size_y) { /* growing? */ - for (sa = sc->areabase.first; sa; sa = sa->next) { - ScrEdge *se = NULL; - - if (sa->temp == 0) - continue; - - if (sa->v1 == sa->v2) - continue; - - /* adjust headery if verts are along the edge of window */ - if (sa->temp == TEMP_TOP) { - /* lower edge */ - const int yval = sa->v2->vec.y - headery_init; - se = BKE_screen_find_edge(sc, sa->v4, sa->v1); - if (se != NULL) { - select_connected_scredge(win, se); - } - for (sv = sc->vertbase.first; sv; sv = sv->next) { - if (sv != sa->v2 && sv != sa->v3) { - if (sv->flag) { - sv->vec.y = yval; - } - } - } - } - else { - /* upper edge */ - const int yval = sa->v1->vec.y + headery_init; - se = BKE_screen_find_edge(sc, sa->v2, sa->v3); - if (se != NULL) { - select_connected_scredge(win, se); - } - for (sv = sc->vertbase.first; sv; sv = sv->next) { - if (sv != sa->v1 && sv != sa->v4) { - if (sv->flag) { - sv->vec.y = yval; - } - } - } - } - } - } - -#undef USE_HEADER_SIZE_CLAMP -#undef TEMP_BOTTOM -#undef TEMP_TOP -#endif - - - /* test for collapsed areas. This could happen in some blender version... */ - /* ton: removed option now, it needs Context... */ - - /* make each window at least ED_area_headersize() high */ - for (sa = sc->areabase.first; sa; sa = sa->next) { - int headery = headery_init; - - /* adjust headery if verts are along the edge of window */ - if (sa->v1->vec.y > window_rect->ymin) - headery += U.pixelsize; - if (sa->v2->vec.y < (window_rect->ymax - 1)) - headery += U.pixelsize; - - if (area_geometry_height(sa) < headery) { - /* lower edge */ - ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1); - if (se && sa->v1 != sa->v2) { - const int yval = sa->v2->vec.y - headery + 1; - - select_connected_scredge(win, se); - - /* all selected vertices get the right offset */ - for (sv = sc->vertbase.first; sv; sv = sv->next) { - /* if is a collapsed area */ - if (sv != sa->v2 && sv != sa->v3) { - if (sv->flag) { - sv->vec.y = yval; - } - } - } - } - } - } - - /* Global areas have a fixed size that only changes with the DPI. Here we ensure that exactly this size is set. */ - for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) { - int height = ED_area_global_size_y(area) - 1; - - if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) { - continue; - } - - if (area->v1->vec.y > window_rect->ymin) { - height += U.pixelsize; - } - if (area->v2->vec.y < (window_rect->ymax - 1)) { - height += U.pixelsize; - } - - /* width */ - area->v1->vec.x = area->v2->vec.x = window_rect->xmin; - area->v3->vec.x = area->v4->vec.x = window_rect->xmax - 1; - /* height */ - area->v1->vec.y = area->v4->vec.y = window_rect->ymin; - area->v2->vec.y = area->v3->vec.y = window_rect->ymax - 1; - - switch (area->global->align) { - case GLOBAL_AREA_ALIGN_TOP: - area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - height; - break; - case GLOBAL_AREA_ALIGN_BOTTOM: - area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + height; - break; - } - } -} - /* ****************** EXPORTED API TO OTHER MODULES *************************** */ @@ -854,7 +448,7 @@ void ED_screen_refresh(wmWindowManager *wm, wmWindow *win) WM_window_rect_calc(win, &window_rect); WM_window_screen_rect_calc(win, &screen_rect); /* Get screen bounds __after__ updating window DPI! */ - screen_vertices_scale(win, screen, &window_rect, &screen_rect); + screen_geom_vertices_scale(win, screen); ED_screen_areas_iter(win, screen, area) { /* set spacetype and region callbacks, calls init() */ @@ -1021,10 +615,10 @@ static void screen_cursor_set(wmWindow *win, const int xy[2]) } } else { - ScrEdge *actedge = screen_find_active_scredge(win, screen, xy[0], xy[1]); + ScrEdge *actedge = screen_geom_find_active_scredge(win, screen, xy[0], xy[1]); if (actedge) { - if (scredge_is_horizontal(actedge)) + if (screen_geom_edge_is_horizontal(actedge)) WM_cursor_set(win, CURSOR_Y_MOVE); else WM_cursor_set(win, CURSOR_X_MOVE); @@ -1140,15 +734,15 @@ static ScrArea *screen_area_create_with_geometry( ScrAreaMap *area_map, const rcti *rect, short spacetype) { - ScrVert *bottom_left = screen_addvert_ex(area_map, rect->xmin, rect->ymin); - ScrVert *top_left = screen_addvert_ex(area_map, rect->xmin, rect->ymax); - ScrVert *top_right = screen_addvert_ex(area_map, rect->xmax, rect->ymax); - ScrVert *bottom_right = screen_addvert_ex(area_map, rect->xmax, rect->ymin); - - screen_addedge_ex(area_map, bottom_left, top_left); - screen_addedge_ex(area_map, top_left, top_right); - screen_addedge_ex(area_map, top_right, bottom_right); - screen_addedge_ex(area_map, bottom_right, bottom_left); + ScrVert *bottom_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymin); + ScrVert *top_left = screen_geom_vertex_add_ex(area_map, rect->xmin, rect->ymax); + ScrVert *top_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymax); + ScrVert *bottom_right = screen_geom_vertex_add_ex(area_map, rect->xmax, rect->ymin); + + screen_geom_edge_add_ex(area_map, bottom_left, top_left); + screen_geom_edge_add_ex(area_map, top_left, top_right); + screen_geom_edge_add_ex(area_map, top_right, bottom_right); + screen_geom_edge_add_ex(area_map, bottom_right, bottom_left); return screen_addarea_ex(area_map, bottom_left, top_left, top_right, bottom_right, spacetype); } diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c new file mode 100644 index 00000000000..5d87479e371 --- /dev/null +++ b/source/blender/editors/screen/screen_geometry.c @@ -0,0 +1,462 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/editors/screen/screen_geometry.c + * \ingroup edscr + * \brief Functions for screen vertices and edges + * + * Screen geometry refers to the vertices (ScrVert) and edges (ScrEdge) through + * which the flexible screen-layout system of Blender is established. + */ + +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_rect.h" + +#include "BKE_screen.h" + +#include "DNA_screen_types.h" +#include "DNA_windowmanager_types.h" + +#include "ED_screen.h" + +#include "MEM_guardedalloc.h" + +#include "WM_api.h" + +#include "screen_intern.h" + + +int screen_geom_area_height(const ScrArea *area) +{ + return area->v2->vec.y - area->v1->vec.y + 1; +} +int screen_geom_area_width(const ScrArea *area) +{ + return area->v4->vec.x - area->v1->vec.x + 1; +} + +ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y) +{ + ScrVert *sv = MEM_callocN(sizeof(ScrVert), "addscrvert"); + sv->vec.x = x; + sv->vec.y = y; + + BLI_addtail(&area_map->vertbase, sv); + return sv; +} +ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y) +{ + return screen_geom_vertex_add_ex(AREAMAP_FROM_SCREEN(sc), x, y); +} + +ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2) +{ + ScrEdge *se = MEM_callocN(sizeof(ScrEdge), "addscredge"); + + BKE_screen_sort_scrvert(&v1, &v2); + se->v1 = v1; + se->v2 = v2; + + BLI_addtail(&area_map->edgebase, se); + return se; +} +ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2) +{ + return screen_geom_edge_add_ex(AREAMAP_FROM_SCREEN(sc), v1, v2); +} + +bool screen_geom_edge_is_horizontal(ScrEdge *se) +{ + return (se->v1->vec.y == se->v2->vec.y); +} + +/** + * \param bounds_rect: Either window or screen bounds. Used to exclude edges along window/screen edges. + */ +ScrEdge *screen_geom_area_map_find_active_scredge( + const ScrAreaMap *area_map, + const rcti *bounds_rect, + const int mx, const int my) +{ + int safety = U.widget_unit / 10; + + CLAMP_MIN(safety, 2); + + for (ScrEdge *se = area_map->edgebase.first; se; se = se->next) { + if (screen_geom_edge_is_horizontal(se)) { + if ((se->v1->vec.y > bounds_rect->ymin) && (se->v1->vec.y < (bounds_rect->ymax - 1))) { + short min, max; + min = MIN2(se->v1->vec.x, se->v2->vec.x); + max = MAX2(se->v1->vec.x, se->v2->vec.x); + + if (abs(my - se->v1->vec.y) <= safety && mx >= min && mx <= max) + return se; + } + } + else { + if ((se->v1->vec.x > bounds_rect->xmin) && (se->v1->vec.x < (bounds_rect->xmax - 1))) { + short min, max; + min = MIN2(se->v1->vec.y, se->v2->vec.y); + max = MAX2(se->v1->vec.y, se->v2->vec.y); + + if (abs(mx - se->v1->vec.x) <= safety && my >= min && my <= max) + return se; + } + } + } + + return NULL; +} + +/* need win size to make sure not to include edges along screen edge */ +ScrEdge *screen_geom_find_active_scredge( + const wmWindow *win, const bScreen *screen, + const int mx, const int my) +{ + /* Use layout size (screen excluding global areas) for screen-layout area edges */ + rcti screen_rect; + ScrEdge *se; + + WM_window_screen_rect_calc(win, &screen_rect); + se = screen_geom_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(screen), &screen_rect, mx, my); + + if (!se) { + /* Use entire window size (screen including global areas) for global area edges */ + rcti win_rect; + WM_window_rect_calc(win, &win_rect); + se = screen_geom_area_map_find_active_scredge(&win->global_areas, &win_rect, mx, my); + } + return se; +} + +/** + * \brief Main screen-layout calculation function. + * + * * Scale areas nicely on window size and DPI changes. + * * Ensure areas have a minimum height. + * * Correctly set global areas to their fixed height. + */ +void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc) +{ + /* clamp Y size of header sized areas when expanding windows + * avoids annoying empty space around file menu */ +#define USE_HEADER_SIZE_CLAMP + + rcti window_rect, screen_rect; + + WM_window_rect_calc(win, &window_rect); + WM_window_screen_rect_calc(win, &screen_rect); + + const int headery_init = ED_area_headersize(); + const int screen_size_x = BLI_rcti_size_x(&screen_rect); + const int screen_size_y = BLI_rcti_size_y(&screen_rect); + ScrVert *sv = NULL; + ScrArea *sa; + int screen_size_x_prev, screen_size_y_prev; + float min[2], max[2]; + + /* calculate size */ + min[0] = min[1] = 20000.0f; + max[0] = max[1] = 0.0f; + + for (sv = sc->vertbase.first; sv; sv = sv->next) { + const float fv[2] = {(float)sv->vec.x, (float)sv->vec.y}; + minmax_v2v2_v2(min, max, fv); + } + + screen_size_x_prev = (max[0] - min[0]) + 1; + screen_size_y_prev = (max[1] - min[1]) + 1; + + +#ifdef USE_HEADER_SIZE_CLAMP +#define TEMP_BOTTOM 1 +#define TEMP_TOP 2 + + /* if the window's Y axis grows, clamp header sized areas */ + if (screen_size_y_prev < screen_size_y) { /* growing? */ + const int headery_margin_max = headery_init + 5; + for (sa = sc->areabase.first; sa; sa = sa->next) { + ARegion *ar = BKE_area_find_region_type(sa, RGN_TYPE_HEADER); + sa->temp = 0; + + if (ar && !(ar->flag & RGN_FLAG_HIDDEN)) { + if (sa->v2->vec.y == max[1]) { + if (screen_geom_area_height(sa) < headery_margin_max) { + sa->temp = TEMP_TOP; + } + } + else if (sa->v1->vec.y == min[1]) { + if (screen_geom_area_height(sa) < headery_margin_max) { + sa->temp = TEMP_BOTTOM; + } + } + } + } + } +#endif + + + if (screen_size_x_prev != screen_size_x || screen_size_y_prev != screen_size_y) { + const float facx = ((float)screen_size_x - 1) / ((float)screen_size_x_prev - 1); + const float facy = ((float)screen_size_y - 1) / ((float)screen_size_y_prev - 1); + + /* make sure it fits! */ + for (sv = sc->vertbase.first; sv; sv = sv->next) { + sv->vec.x = screen_rect.xmin + round_fl_to_short((sv->vec.x - min[0]) * facx); + CLAMP(sv->vec.x, screen_rect.xmin, screen_rect.xmax - 1); + + sv->vec.y = screen_rect.ymin + round_fl_to_short((sv->vec.y - min[1]) * facy); + CLAMP(sv->vec.y, screen_rect.ymin, screen_rect.ymax - 1); + } + } + + +#ifdef USE_HEADER_SIZE_CLAMP + if (screen_size_y_prev < screen_size_y) { /* growing? */ + for (sa = sc->areabase.first; sa; sa = sa->next) { + ScrEdge *se = NULL; + + if (sa->temp == 0) + continue; + + if (sa->v1 == sa->v2) + continue; + + /* adjust headery if verts are along the edge of window */ + if (sa->temp == TEMP_TOP) { + /* lower edge */ + const int yval = sa->v2->vec.y - headery_init; + se = BKE_screen_find_edge(sc, sa->v4, sa->v1); + if (se != NULL) { + screen_geom_select_connected_edge(win, se); + } + for (sv = sc->vertbase.first; sv; sv = sv->next) { + if (sv != sa->v2 && sv != sa->v3) { + if (sv->flag) { + sv->vec.y = yval; + } + } + } + } + else { + /* upper edge */ + const int yval = sa->v1->vec.y + headery_init; + se = BKE_screen_find_edge(sc, sa->v2, sa->v3); + if (se != NULL) { + screen_geom_select_connected_edge(win, se); + } + for (sv = sc->vertbase.first; sv; sv = sv->next) { + if (sv != sa->v1 && sv != sa->v4) { + if (sv->flag) { + sv->vec.y = yval; + } + } + } + } + } + } + +#undef USE_HEADER_SIZE_CLAMP +#undef TEMP_BOTTOM +#undef TEMP_TOP +#endif + + + /* test for collapsed areas. This could happen in some blender version... */ + /* ton: removed option now, it needs Context... */ + + /* make each window at least ED_area_headersize() high */ + for (sa = sc->areabase.first; sa; sa = sa->next) { + int headery = headery_init; + + /* adjust headery if verts are along the edge of window */ + if (sa->v1->vec.y > window_rect.ymin) + headery += U.pixelsize; + if (sa->v2->vec.y < (window_rect.ymax - 1)) + headery += U.pixelsize; + + if (screen_geom_area_height(sa) < headery) { + /* lower edge */ + ScrEdge *se = BKE_screen_find_edge(sc, sa->v4, sa->v1); + if (se && sa->v1 != sa->v2) { + const int yval = sa->v2->vec.y - headery + 1; + + screen_geom_select_connected_edge(win, se); + + /* all selected vertices get the right offset */ + for (sv = sc->vertbase.first; sv; sv = sv->next) { + /* if is a collapsed area */ + if (sv != sa->v2 && sv != sa->v3) { + if (sv->flag) { + sv->vec.y = yval; + } + } + } + } + } + } + + /* Global areas have a fixed size that only changes with the DPI. Here we ensure that exactly this size is set. */ + for (ScrArea *area = win->global_areas.areabase.first; area; area = area->next) { + if (area->global->flag & GLOBAL_AREA_IS_HIDDEN) { + continue; + } + + int height = ED_area_global_size_y(area) - 1; + + if (area->v1->vec.y > window_rect.ymin) { + height += U.pixelsize; + } + if (area->v2->vec.y < (window_rect.ymax - 1)) { + height += U.pixelsize; + } + + /* width */ + area->v1->vec.x = area->v2->vec.x = window_rect.xmin; + area->v3->vec.x = area->v4->vec.x = window_rect.xmax - 1; + /* height */ + area->v1->vec.y = area->v4->vec.y = window_rect.ymin; + area->v2->vec.y = area->v3->vec.y = window_rect.ymax - 1; + + switch (area->global->align) { + case GLOBAL_AREA_ALIGN_TOP: + area->v1->vec.y = area->v4->vec.y = area->v2->vec.y - height; + break; + case GLOBAL_AREA_ALIGN_BOTTOM: + area->v2->vec.y = area->v3->vec.y = area->v1->vec.y + height; + break; + } + } +} + +/** + * \return 0 if no split is possible, otherwise the screen-coordinate at which to split. + */ +short screen_geom_find_area_split_point(const ScrArea *sa, const rcti *window_rect, char dir, float fac) +{ + short x, y; + const int cur_area_width = screen_geom_area_width(sa); + const int cur_area_height = screen_geom_area_height(sa); + const short area_min_x = AREAMINX; + const short area_min_y = ED_area_headersize(); + int area_min; + + // area big enough? + if ((dir == 'v') && (cur_area_width <= 2 * area_min_x)) { + return 0; + } + if ((dir == 'h') && (cur_area_height <= 2 * area_min_y)) { + return 0; + } + + // to be sure + CLAMP(fac, 0.0f, 1.0f); + + if (dir == 'h') { + y = sa->v1->vec.y + round_fl_to_short(fac * cur_area_height); + + area_min = area_min_y; + + if (sa->v1->vec.y > window_rect->ymin) { + area_min += U.pixelsize; + } + if (sa->v2->vec.y < (window_rect->ymax - 1)) { + area_min += U.pixelsize; + } + + if (y - sa->v1->vec.y < area_min) { + y = sa->v1->vec.y + area_min; + } + else if (sa->v2->vec.y - y < area_min) { + y = sa->v2->vec.y - area_min; + } + + return y; + } + else { + x = sa->v1->vec.x + round_fl_to_short(fac * cur_area_width); + + area_min = area_min_x; + + if (sa->v1->vec.x > window_rect->xmin) { + area_min += U.pixelsize; + } + if (sa->v4->vec.x < (window_rect->xmax - 1)) { + area_min += U.pixelsize; + } + + if (x - sa->v1->vec.x < area_min) { + x = sa->v1->vec.x + area_min; + } + else if (sa->v4->vec.x - x < area_min) { + x = sa->v4->vec.x - area_min; + } + + return x; + } +} + +/** + * Select all edges that are directly or indirectly connected to \a edge. + */ +void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge) +{ + bScreen *sc = WM_window_get_active_screen(win); + bool oneselected = true; + char dir; + + /* select connected, only in the right direction */ + /* 'dir' is the direction of EDGE */ + + if (edge->v1->vec.x == edge->v2->vec.x) { + dir = 'v'; + } + else { + dir = 'h'; + } + + ED_screen_verts_iter(win, sc, sv) { + sv->flag = 0; + } + + edge->v1->flag = 1; + edge->v2->flag = 1; + + while (oneselected) { + oneselected = false; + for (ScrEdge *se = sc->edgebase.first; se; se = se->next) { + if (se->v1->flag + se->v2->flag == 1) { + if (dir == 'h') { + if (se->v1->vec.y == se->v2->vec.y) { + se->v1->flag = se->v2->flag = 1; + oneselected = true; + } + } + if (dir == 'v') { + if (se->v1->vec.x == se->v2->vec.x) { + se->v1->flag = se->v2->flag = 1; + oneselected = true; + } + } + } + } + } +} diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index 0cfe76cdeb8..cd71c07a3c0 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -55,22 +55,30 @@ void screen_change_update(struct bContext *C, wmWindow *win, bScreen *sc) bScreen *screen_change_prepare(bScreen *screen_old, bScreen *screen_new, struct Main *bmain, struct bContext *C, wmWindow *win); ScrArea *area_split(const wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac, int merge); int screen_area_join(struct bContext *C, bScreen *scr, ScrArea *sa1, ScrArea *sa2); -int area_geometry_height(const ScrArea *area); -int area_geometry_width(const ScrArea *area); int area_getorientation(ScrArea *sa, ScrArea *sb); -void select_connected_scredge(const wmWindow *win, ScrEdge *edge); -bool scredge_is_horizontal(ScrEdge *se); -ScrEdge *screen_area_map_find_active_scredge( +struct AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2]); +struct AZone *ED_area_actionzone_refresh_xy(ScrArea *sa, const int xy[2]); + +/* screen_geometry.c */ +int screen_geom_area_height(const ScrArea *area); +int screen_geom_area_width(const ScrArea *area); +ScrVert *screen_geom_vertex_add_ex(ScrAreaMap *area_map, short x, short y); +ScrVert *screen_geom_vertex_add(bScreen *sc, short x, short y); +ScrEdge *screen_geom_edge_add_ex(ScrAreaMap *area_map, ScrVert *v1, ScrVert *v2); +ScrEdge *screen_geom_edge_add(bScreen *sc, ScrVert *v1, ScrVert *v2); +bool screen_geom_edge_is_horizontal(ScrEdge *se); +ScrEdge *screen_geom_area_map_find_active_scredge( const struct ScrAreaMap *area_map, const rcti *bounds_rect, const int mx, const int my); -ScrEdge *screen_find_active_scredge( +ScrEdge *screen_geom_find_active_scredge( const wmWindow *win, const bScreen *screen, const int mx, const int my); +void screen_geom_vertices_scale(const wmWindow *win, bScreen *sc); +short screen_geom_find_area_split_point(const ScrArea *sa, const rcti *window_rect, char dir, float fac); +void screen_geom_select_connected_edge(const wmWindow *win, ScrEdge *edge); -struct AZone *ED_area_actionzone_find_xy(ScrArea *sa, const int xy[2]); -struct AZone *ED_area_actionzone_refresh_xy(ScrArea *sa, const int xy[2]); /* screen_context.c */ int ed_screen_context( diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 9c27bda5ec8..90d33fbde03 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -900,7 +900,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* once we drag outside the actionzone, register a gesture * check we're not on an edge so join finds the other area */ is_gesture = ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) && - (screen_area_map_find_active_scredge( + (screen_geom_area_map_find_active_scredge( AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y) == NULL)); } else { @@ -1282,7 +1282,7 @@ static void area_move_set_limits( if (sa->v2->vec.y < (window_rect.ymax - 1)) areamin += U.pixelsize; - y1 = area_geometry_height(sa) - areamin; + y1 = screen_geom_area_height(sa) - areamin; /* if top or down edge selected, test height */ if (sa->v1->editflag && sa->v4->editflag) @@ -1299,7 +1299,7 @@ static void area_move_set_limits( if (sa->v4->vec.x < (window_rect.xmax - 1)) areamin += U.pixelsize; - x1 = area_geometry_width(sa) - areamin; + x1 = screen_geom_area_width(sa) - areamin; /* if left or right edge selected, test width */ if (sa->v1->editflag && sa->v2->editflag) @@ -1325,17 +1325,17 @@ static int area_move_init(bContext *C, wmOperator *op) y = RNA_int_get(op->ptr, "y"); /* setup */ - actedge = screen_find_active_scredge(win, sc, x, y); + actedge = screen_geom_find_active_scredge(win, sc, x, y); if (actedge == NULL) return 0; md = MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData"); op->customdata = md; - md->dir = scredge_is_horizontal(actedge) ? 'h' : 'v'; + md->dir = screen_geom_edge_is_horizontal(actedge) ? 'h' : 'v'; if (md->dir == 'h') md->origval = actedge->v1->vec.y; else md->origval = actedge->v1->vec.x; - select_connected_scredge(win, actedge); + screen_geom_select_connected_edge(win, actedge); /* now all vertices with 'flag == 1' are the ones that can be moved. Move this to editflag */ ED_screen_verts_iter(win, sc, v1) { v1->editflag = v1->flag; @@ -1460,7 +1460,7 @@ static void area_move_apply_do( ED_screen_areas_iter(win, sc, sa) { if (sa->v1->editflag || sa->v2->editflag || sa->v3->editflag || sa->v4->editflag) { if (ED_area_is_global(sa)) { - sa->global->cur_fixed_height = round_fl_to_int(area_geometry_height(sa) / UI_DPI_FAC); + sa->global->cur_fixed_height = round_fl_to_int(screen_geom_area_height(sa) / UI_DPI_FAC); sc->do_refresh = true; redraw_all = true; } @@ -1881,11 +1881,11 @@ static int area_split_invoke(bContext *C, wmOperator *op, const wmEvent *event) WM_window_screen_rect_calc(win, &screen_rect); - actedge = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, x, y); + actedge = screen_geom_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, x, y); if (actedge == NULL) return OPERATOR_CANCELLED; - dir = scredge_is_horizontal(actedge) ? 'v' : 'h'; + dir = screen_geom_edge_is_horizontal(actedge) ? 'v' : 'h'; RNA_enum_set(op->ptr, "direction", dir); @@ -3112,7 +3112,7 @@ static int screen_area_options_invoke(bContext *C, wmOperator *op, const wmEvent rcti screen_rect; WM_window_screen_rect_calc(win, &screen_rect); - actedge = screen_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y); + actedge = screen_geom_area_map_find_active_scredge(AREAMAP_FROM_SCREEN(sc), &screen_rect, event->x, event->y); if (actedge == NULL) return OPERATOR_CANCELLED; |