Blender  V3.3
workspace_layout_edit.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include <stdlib.h>
8 
9 #include "BLI_listbase.h"
10 #include "BLI_utildefines.h"
11 
12 #include "DNA_screen_types.h"
13 #include "DNA_workspace_types.h"
14 
15 #include "BKE_context.h"
16 #include "BKE_main.h"
17 #include "BKE_screen.h"
18 #include "BKE_workspace.h"
19 
20 #include "WM_api.h"
21 
22 #include "ED_screen.h"
23 
24 #include "screen_intern.h"
25 
27  WorkSpace *workspace,
28  wmWindow *win,
29  const char *name)
30 {
31  bScreen *screen;
32  rcti screen_rect;
33 
34  WM_window_screen_rect_calc(win, &screen_rect);
35  screen = screen_add(bmain, name, &screen_rect);
36 
37  return BKE_workspace_layout_add(bmain, workspace, screen, name);
38 }
39 
41  WorkSpace *workspace,
42  const WorkSpaceLayout *layout_old,
43  wmWindow *win)
44 {
45  bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
46  const char *name = BKE_workspace_layout_name_get(layout_old);
47 
48  WorkSpaceLayout *layout_new = ED_workspace_layout_add(bmain, workspace, win, name);
49  bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
50 
51  if (BKE_screen_is_fullscreen_area(screen_old)) {
52  LISTBASE_FOREACH (ScrArea *, area_old, &screen_old->areabase) {
53  if (area_old->full) {
54  ScrArea *area_new = (ScrArea *)screen_new->areabase.first;
55  ED_area_data_copy(area_new, area_old, true);
56  ED_area_tag_redraw(area_new);
57  break;
58  }
59  }
60  }
61  else {
62  screen_data_copy(screen_new, screen_old);
63  }
64 
65  return layout_new;
66 }
67 
68 static bool workspace_layout_delete_doit(WorkSpace *workspace,
69  WorkSpaceLayout *layout_old,
70  WorkSpaceLayout *layout_new,
71  bContext *C)
72 {
73  Main *bmain = CTX_data_main(C);
74  wmWindow *win = CTX_wm_window(C);
75  bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
76 
77  ED_screen_change(C, screen_new);
78 
79  if (BKE_workspace_active_layout_get(win->workspace_hook) != layout_old) {
80  BKE_workspace_layout_remove(bmain, workspace, layout_old);
81  return true;
82  }
83 
84  return false;
85 }
86 
88 {
89  const bScreen *screen = BKE_workspace_layout_screen_get(layout);
90 
91  return ((BKE_screen_is_used(screen) == false) &&
92  /* in typical usage temp screens should have a nonzero winid
93  * (all temp screens should be used, or closed & freed). */
94  (screen->temp == false) && (BKE_screen_is_fullscreen_area(screen) == false) &&
95  (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
96 }
97 
99 {
100  for (WorkSpaceLayout *layout_new = layout_old->prev; layout_new; layout_new = layout_new->next) {
101  if (workspace_layout_set_poll(layout_new)) {
102  return layout_new;
103  }
104  }
105 
106  for (WorkSpaceLayout *layout_new = layout_old->next; layout_new; layout_new = layout_new->next) {
107  if (workspace_layout_set_poll(layout_new)) {
108  return layout_new;
109  }
110  }
111 
112  return NULL;
113 }
114 
116 {
117  const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
118  WorkSpaceLayout *layout_new;
119 
120  BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1);
121 
122  /* Don't allow deleting temp full-screens for now. */
123  if (BKE_screen_is_fullscreen_area(screen_old)) {
124  return false;
125  }
126 
127  /* A layout/screen can only be in use by one window at a time, so as
128  * long as we are able to find a layout/screen that is unused, we
129  * can safely assume ours is not in use anywhere an delete it. */
130 
131  layout_new = workspace_layout_delete_find_new(layout_old);
132 
133  if (layout_new) {
134  return workspace_layout_delete_doit(workspace, layout_old, layout_new, C);
135  }
136 
137  return false;
138 }
139 
140 static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
141 {
142  /* return false to stop the iterator if we've found a layout that can be activated */
143  return workspace_layout_set_poll(layout) ? false : true;
144 }
145 
147 {
148  LISTBASE_FOREACH (bScreen *, screen_iter, &bmain->screens) {
149  if ((screen_iter != screen) && ELEM(screen_iter->state, SCREENMAXIMIZED, SCREENFULL)) {
150  ScrArea *area = screen_iter->areabase.first;
151  if (area && area->full == screen) {
152  return screen_iter;
153  }
154  }
155  }
156 
157  return screen;
158 }
159 
160 static bool screen_is_used_by_other_window(const wmWindow *win, const bScreen *screen)
161 {
162  return BKE_screen_is_used(screen) && (screen->winid != win->winid);
163 }
164 
166  Main *bmain,
167  WorkSpace *workspace,
168  WorkSpaceLayout *layout_new,
169  const WorkSpaceLayout *layout_fallback_base,
170  wmWindow *win)
171 {
172  WorkSpaceLayout *layout_temp = layout_new;
173  bScreen *screen_temp = BKE_workspace_layout_screen_get(layout_new);
174 
175  screen_temp = screen_fullscreen_find_associated_normal_screen(bmain, screen_temp);
176  layout_temp = BKE_workspace_layout_find(workspace, screen_temp);
177 
178  if (screen_is_used_by_other_window(win, screen_temp)) {
179  /* Screen is already used, try to find a free one. */
181  workspace, layout_new, workspace_change_find_new_layout_cb, NULL, false);
182  screen_temp = layout_temp ? BKE_workspace_layout_screen_get(layout_temp) : NULL;
183 
184  if (!layout_temp || screen_is_used_by_other_window(win, screen_temp)) {
185  /* Fallback solution: duplicate layout. */
186  layout_temp = ED_workspace_layout_duplicate(bmain, workspace, layout_fallback_base, win);
187  }
188  }
189 
190  return layout_temp;
191 }
192 
193 static bool workspace_layout_cycle_iter_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
194 {
195  /* return false to stop iterator when we have found a layout to activate */
196  return !workspace_layout_set_poll(layout);
197 }
198 
199 bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bContext *C)
200 {
201  wmWindow *win = CTX_wm_window(C);
203  const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout);
205 
206  if (old_screen->temp || (area && area->full && area->full->temp)) {
207  return false;
208  }
209 
210  BLI_assert(ELEM(direction, 1, -1));
211  WorkSpaceLayout *new_layout = BKE_workspace_layout_iter_circular(workspace,
212  old_layout,
214  NULL,
215  (direction == -1) ? true :
216  false);
217 
218  if (new_layout && (old_layout != new_layout)) {
219  bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout);
220 
221  if (area && area->full) {
222  /* return to previous state before switching screens */
223  ED_screen_full_restore(C, area); /* may free screen of old_layout */
224  }
225 
226  ED_screen_change(C, new_screen);
227 
228  return true;
229  }
230 
231  return false;
232 }
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:738
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:723
bool BKE_screen_is_used(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BKE_screen_is_fullscreen_area(const struct bScreen *screen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
void BKE_workspace_layout_remove(struct Main *bmain, struct WorkSpace *workspace, struct WorkSpaceLayout *layout) ATTR_NONNULL()
Definition: workspace.c:383
struct WorkSpaceLayout * BKE_workspace_layout_add(struct Main *bmain, struct WorkSpace *workspace, struct bScreen *screen, const char *name) ATTR_NONNULL()
Definition: workspace.c:364
struct WorkSpaceLayout struct WorkSpaceLayout * BKE_workspace_layout_iter_circular(const struct WorkSpace *workspace, struct WorkSpaceLayout *start, bool(*callback)(const struct WorkSpaceLayout *layout, void *arg), void *arg, bool iter_backward)
const char * BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS
struct WorkSpaceLayout * BKE_workspace_active_layout_get(const struct WorkSpaceInstanceHook *hook) GETTER_ATTRS
struct bScreen * BKE_workspace_layout_screen_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS
struct WorkSpaceLayout * BKE_workspace_layout_find(const struct WorkSpace *workspace, const struct bScreen *screen) ATTR_NONNULL() ATTR_WARN_UNUSED_RESULT
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define UNUSED(x)
#define ELEM(...)
@ SCREENFULL
@ SCREENMAXIMIZED
@ USER_HIDE_DOT
void ED_area_tag_redraw(ScrArea *area)
Definition: area.c:729
void ED_screen_full_restore(struct bContext *C, ScrArea *area)
Definition: screen_edit.c:1304
bool ED_screen_change(struct bContext *C, struct bScreen *screen)
Change the active screen.
Definition: screen_edit.c:1135
#define C
Definition: RandGen.cpp:25
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition: area.c:2122
unsigned int U
Definition: btGjkEpa3.h:78
static void area(int d1, int d2, int e1, int e2, float weights[2])
void screen_data_copy(bScreen *to, bScreen *from)
Definition: screen_edit.c:212
bScreen * screen_add(Main *bmain, const char *name, const rcti *rect)
Definition: screen_edit.c:190
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
ListBase screens
Definition: BKE_main.h:183
Wrapper for bScreen.
struct WorkSpaceLayout * next
struct WorkSpaceLayout * prev
ListBase areabase
struct WorkSpaceInstanceHook * workspace_hook
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
Definition: wm_window.c:2093
static bool workspace_layout_cycle_iter_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
bool workspace_layout_set_poll(const WorkSpaceLayout *layout)
static bScreen * screen_fullscreen_find_associated_normal_screen(const Main *bmain, bScreen *screen)
static bool workspace_layout_delete_doit(WorkSpace *workspace, WorkSpaceLayout *layout_old, WorkSpaceLayout *layout_new, bContext *C)
WorkSpaceLayout * ED_workspace_layout_duplicate(Main *bmain, WorkSpace *workspace, const WorkSpaceLayout *layout_old, wmWindow *win)
static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bContext *C)
WorkSpaceLayout * ED_workspace_layout_add(Main *bmain, WorkSpace *workspace, wmWindow *win, const char *name)
bool ED_workspace_layout_delete(WorkSpace *workspace, WorkSpaceLayout *layout_old, bContext *C)
static bool screen_is_used_by_other_window(const wmWindow *win, const bScreen *screen)
static WorkSpaceLayout * workspace_layout_delete_find_new(const WorkSpaceLayout *layout_old)
WorkSpaceLayout * ED_workspace_screen_change_ensure_unused_layout(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout_new, const WorkSpaceLayout *layout_fallback_base, wmWindow *win)