Blender  V2.93
workspace_layout_edit.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  */
16 
21 #include <stdlib.h>
22 
23 #include "BLI_listbase.h"
24 #include "BLI_utildefines.h"
25 
26 #include "DNA_screen_types.h"
27 #include "DNA_workspace_types.h"
28 
29 #include "BKE_context.h"
30 #include "BKE_main.h"
31 #include "BKE_screen.h"
32 #include "BKE_workspace.h"
33 
34 #include "WM_api.h"
35 
36 #include "ED_screen.h"
37 
38 #include "screen_intern.h"
39 
44  WorkSpace *workspace,
45  wmWindow *win,
46  const char *name)
47 {
48  bScreen *screen;
49  rcti screen_rect;
50 
51  WM_window_screen_rect_calc(win, &screen_rect);
52  screen = screen_add(bmain, name, &screen_rect);
53 
54  return BKE_workspace_layout_add(bmain, workspace, screen, name);
55 }
56 
58  WorkSpace *workspace,
59  const WorkSpaceLayout *layout_old,
60  wmWindow *win)
61 {
62  bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
63  const char *name = BKE_workspace_layout_name_get(layout_old);
64 
65  WorkSpaceLayout *layout_new = ED_workspace_layout_add(bmain, workspace, win, name);
66  bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
67 
68  if (BKE_screen_is_fullscreen_area(screen_old)) {
69  LISTBASE_FOREACH (ScrArea *, area_old, &screen_old->areabase) {
70  if (area_old->full) {
71  ScrArea *area_new = (ScrArea *)screen_new->areabase.first;
72  ED_area_data_copy(area_new, area_old, true);
73  ED_area_tag_redraw(area_new);
74  break;
75  }
76  }
77  }
78  else {
79  screen_data_copy(screen_new, screen_old);
80  }
81 
82  return layout_new;
83 }
84 
85 static bool workspace_layout_delete_doit(WorkSpace *workspace,
86  WorkSpaceLayout *layout_old,
87  WorkSpaceLayout *layout_new,
88  bContext *C)
89 {
90  Main *bmain = CTX_data_main(C);
91  wmWindow *win = CTX_wm_window(C);
92  bScreen *screen_new = BKE_workspace_layout_screen_get(layout_new);
93 
94  ED_screen_change(C, screen_new);
95 
96  if (BKE_workspace_active_layout_get(win->workspace_hook) != layout_old) {
97  BKE_workspace_layout_remove(bmain, workspace, layout_old);
98  return true;
99  }
100 
101  return false;
102 }
103 
105 {
106  const bScreen *screen = BKE_workspace_layout_screen_get(layout);
107 
108  return ((BKE_screen_is_used(screen) == false) &&
109  /* in typical usage temp screens should have a nonzero winid
110  * (all temp screens should be used, or closed & freed). */
111  (screen->temp == false) && (BKE_screen_is_fullscreen_area(screen) == false) &&
112  (screen->id.name[2] != '.' || !(U.uiflag & USER_HIDE_DOT)));
113 }
114 
116 {
117  for (WorkSpaceLayout *layout_new = layout_old->prev; layout_new; layout_new = layout_new->next) {
118  if (workspace_layout_set_poll(layout_new)) {
119  return layout_new;
120  }
121  }
122 
123  for (WorkSpaceLayout *layout_new = layout_old->next; layout_new; layout_new = layout_new->next) {
124  if (workspace_layout_set_poll(layout_new)) {
125  return layout_new;
126  }
127  }
128 
129  return NULL;
130 }
131 
137 {
138  const bScreen *screen_old = BKE_workspace_layout_screen_get(layout_old);
139  WorkSpaceLayout *layout_new;
140 
141  BLI_assert(BLI_findindex(&workspace->layouts, layout_old) != -1);
142 
143  /* don't allow deleting temp fullscreens for now */
144  if (BKE_screen_is_fullscreen_area(screen_old)) {
145  return false;
146  }
147 
148  /* A layout/screen can only be in use by one window at a time, so as
149  * long as we are able to find a layout/screen that is unused, we
150  * can safely assume ours is not in use anywhere an delete it. */
151 
152  layout_new = workspace_layout_delete_find_new(layout_old);
153 
154  if (layout_new) {
155  return workspace_layout_delete_doit(workspace, layout_old, layout_new, C);
156  }
157 
158  return false;
159 }
160 
161 static bool workspace_change_find_new_layout_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
162 {
163  /* return false to stop the iterator if we've found a layout that can be activated */
164  return workspace_layout_set_poll(layout) ? false : true;
165 }
166 
168 {
169  LISTBASE_FOREACH (bScreen *, screen_iter, &bmain->screens) {
170  if ((screen_iter != screen) && ELEM(screen_iter->state, SCREENMAXIMIZED, SCREENFULL)) {
171  ScrArea *area = screen_iter->areabase.first;
172  if (area && area->full == screen) {
173  return screen_iter;
174  }
175  }
176  }
177 
178  return screen;
179 }
180 
181 static bool screen_is_used_by_other_window(const wmWindow *win, const bScreen *screen)
182 {
183  return BKE_screen_is_used(screen) && (screen->winid != win->winid);
184 }
185 
193  Main *bmain,
194  WorkSpace *workspace,
195  WorkSpaceLayout *layout_new,
196  const WorkSpaceLayout *layout_fallback_base,
197  wmWindow *win)
198 {
199  WorkSpaceLayout *layout_temp = layout_new;
200  bScreen *screen_temp = BKE_workspace_layout_screen_get(layout_new);
201 
202  screen_temp = screen_fullscreen_find_associated_normal_screen(bmain, screen_temp);
203  layout_temp = BKE_workspace_layout_find(workspace, screen_temp);
204 
205  if (screen_is_used_by_other_window(win, screen_temp)) {
206  /* Screen is already used, try to find a free one. */
208  workspace, layout_new, workspace_change_find_new_layout_cb, NULL, false);
209  screen_temp = layout_temp ? BKE_workspace_layout_screen_get(layout_temp) : NULL;
210 
211  if (!layout_temp || screen_is_used_by_other_window(win, screen_temp)) {
212  /* Fallback solution: duplicate layout. */
213  layout_temp = ED_workspace_layout_duplicate(bmain, workspace, layout_fallback_base, win);
214  }
215  }
216 
217  return layout_temp;
218 }
219 
220 static bool workspace_layout_cycle_iter_cb(const WorkSpaceLayout *layout, void *UNUSED(arg))
221 {
222  /* return false to stop iterator when we have found a layout to activate */
223  return !workspace_layout_set_poll(layout);
224 }
225 
226 bool ED_workspace_layout_cycle(WorkSpace *workspace, const short direction, bContext *C)
227 {
228  wmWindow *win = CTX_wm_window(C);
230  const bScreen *old_screen = BKE_workspace_layout_screen_get(old_layout);
232 
233  if (old_screen->temp || (area && area->full && area->full->temp)) {
234  return false;
235  }
236 
237  BLI_assert(ELEM(direction, 1, -1));
238  WorkSpaceLayout *new_layout = BKE_workspace_layout_iter_circular(workspace,
239  old_layout,
241  NULL,
242  (direction == -1) ? true :
243  false);
244 
245  if (new_layout && (old_layout != new_layout)) {
246  bScreen *new_screen = BKE_workspace_layout_screen_get(new_layout);
247 
248  if (area && area->full) {
249  /* return to previous state before switching screens */
250  ED_screen_full_restore(C, area); /* may free screen of old_layout */
251  }
252 
253  ED_screen_change(C, new_screen);
254 
255  return true;
256  }
257 
258  return false;
259 }
struct ScrArea * CTX_wm_area(const bContext *C)
Definition: context.c:714
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1018
struct wmWindow * CTX_wm_window(const bContext *C)
Definition: context.c:699
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:386
struct WorkSpaceLayout * BKE_workspace_layout_add(struct Main *bmain, struct WorkSpace *workspace, struct bScreen *screen, const char *name) ATTR_NONNULL()
Definition: workspace.c:367
const char * BKE_workspace_layout_name_get(const struct WorkSpaceLayout *layout) GETTER_ATTRS
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, const bool iter_backward)
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:58
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
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:745
void ED_screen_full_restore(struct bContext *C, ScrArea *area)
Definition: screen_edit.c:1198
bool ED_screen_change(struct bContext *C, struct bScreen *screen)
Change the active screen.
Definition: screen_edit.c:1039
#define C
Definition: RandGen.cpp:39
void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free)
Definition: area.c:2067
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:226
bScreen * screen_add(Main *bmain, const char *name, const rcti *rect)
Definition: screen_edit.c:204
char name[66]
Definition: DNA_ID.h:283
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase screens
Definition: BKE_main.h:161
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:2154
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)