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