UI: Save Temp Window Sizes & Positions

Allow temporary windows (like File Browser, Preferences, Render,
Drivers, Info) to open at their last positions and sizes.

Pull Request: https://projects.blender.org/blender/blender/pulls/104727
This commit is contained in:
Harley Acheson
2025-09-05 00:05:50 +02:00
committed by Harley Acheson
parent ccd8926717
commit 91997ea89f
18 changed files with 184 additions and 196 deletions

View File

@@ -178,6 +178,10 @@ typedef enum {
* Setting cursors via #GHOST_SetCursorGenerator is supported.
*/
GHOST_kCapabilityCursorGenerator = (1 << 11),
/**
* Support accurately placing windows on multiple monitors.
*/
GHOST_kCapabilityMultiMonitorPlacement = (1 << 12),
} GHOST_TCapabilityFlag;
@@ -191,7 +195,7 @@ typedef enum {
GHOST_kCapabilityClipboardImage | GHOST_kCapabilityDesktopSample | GHOST_kCapabilityInputIME | \
GHOST_kCapabilityTrackpadPhysicalDirection | GHOST_kCapabilityWindowDecorationStyles | \
GHOST_kCapabilityKeyboardHyperKey | GHOST_kCapabilityCursorRGBA | \
GHOST_kCapabilityCursorGenerator)
GHOST_kCapabilityCursorGenerator | GHOST_kCapabilityMultiMonitorPlacement)
/* Xtilt and Ytilt represent how much the pen is tilted away from
* vertically upright in either the X or Y direction, with X and Y the

View File

@@ -76,7 +76,9 @@ class GHOST_SystemHeadless : public GHOST_System {
/* Wrap. */
GHOST_kCapabilityCursorRGBA |
/* Wrap. */
GHOST_kCapabilityCursorGenerator)
GHOST_kCapabilityCursorGenerator |
/* Wrap. */
GHOST_kCapabilityMultiMonitorPlacement)
);
}

View File

@@ -801,6 +801,8 @@ GHOST_TCapabilityFlag GHOST_SystemSDL::getCapabilities() const
GHOST_kCapabilityInputIME |
/* No support for window decoration styles. */
GHOST_kCapabilityWindowDecorationStyles |
/* No support for precisely placing windows on multiple monitors. */
GHOST_kCapabilityMultiMonitorPlacement |
/* No support for a Hyper modifier key. */
GHOST_kCapabilityKeyboardHyperKey |
/* No support yet for RGBA mouse cursors. */

View File

@@ -9074,6 +9074,8 @@ GHOST_TCapabilityFlag GHOST_SystemWayland::getCapabilities() const
~(
/* WAYLAND doesn't support accessing the window position. */
GHOST_kCapabilityWindowPosition |
/* WAYLAND cannot precisely place windows among multiple monitors. */
GHOST_kCapabilityMultiMonitorPlacement |
/* WAYLAND doesn't support setting the cursor position directly,
* this is an intentional choice, forcing us to use a software cursor in this case. */
GHOST_kCapabilityCursorWarp |

View File

@@ -221,9 +221,16 @@ const UserDef U_default = {
.details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME,
.flag = FILE_HIDE_DOT,
.filter_id = FILTER_ID_ALL,
},
.temp_win_sizex = 1060,
.temp_win_sizey = 600,
.stored_bounds =
{
.file = {100.0f, 1160.0f, 350.0f, 950.0f},
.userpref = {100.0f, 940.0f, 350.0f, 900.0f},
.image = {50.0f, 1360.0f, 50.0f, 830.0f},
.graph = {50.0f, 950.0f, 200.0f, 780.0f},
.info = {100.0f, 1000.0f, 300.0f, 880.0f},
.outliner = {100.0f, 550.0f, 350.0f, 800.0f},
},
.sequencer_proxy_setup = USER_SEQ_PROXY_SETUP_AUTOMATIC,

View File

@@ -27,7 +27,7 @@
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
#define BLENDER_FILE_SUBVERSION 75
#define BLENDER_FILE_SUBVERSION 76
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and cancel loading the file, showing a warning to

View File

@@ -1670,6 +1670,12 @@ void blo_do_versions_userdef(UserDef *userdef)
userdef->preferences_display_type = USER_TEMP_SPACE_DISPLAY_WINDOW;
}
if (!USER_VERSION_ATLEAST(500, 76)) {
if (userdef->stored_bounds.file.xmin == userdef->stored_bounds.file.xmax) {
memcpy(&userdef->stored_bounds, &U_default.stored_bounds, sizeof(userdef->stored_bounds));
}
}
/**
* Always bump subversion in BKE_blender_version.h when adding versioning
* code here, and wrap it inside a USER_VERSION_ATLEAST check.

View File

@@ -125,9 +125,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile);
* \param temp_win_size: If the browser was opened in a temporary window,
* pass its size here so we can store that in the preferences. Otherwise NULL.
*/
void ED_fileselect_params_to_userdef(SpaceFile *sfile,
const int temp_win_size[2],
bool is_maximized);
void ED_fileselect_params_to_userdef(SpaceFile *sfile);
void ED_fileselect_init_layout(SpaceFile *sfile, ARegion *region);

View File

@@ -389,10 +389,9 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, short
*/
ScrArea *ED_screen_temp_space_open(bContext *C,
const char *title,
const rcti *rect_unscaled,
eSpace_Type space_type,
int display_type,
bool dialog) ATTR_NONNULL(1, 3);
bool dialog) ATTR_NONNULL(1);
void ED_screens_header_tools_menu_create(bContext *C, uiLayout *layout, void *arg);
void ED_screens_footer_tools_menu_create(bContext *C, uiLayout *layout, void *arg);
void ED_screens_region_flip_menu_create(bContext *C, uiLayout *layout, void *arg);

View File

@@ -149,6 +149,16 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
sizex = std::max(sizex, 320);
sizey = std::max(sizey, 256);
WM_window_dpi_set_userdef(CTX_wm_window(C));
rctf *stored_bounds = &U.stored_bounds.image;
const bool bounds_valid = (stored_bounds && (BLI_rctf_size_x(stored_bounds) > 150.0f) &&
(BLI_rctf_size_y(stored_bounds) > 100.0f));
const bool mm_placement = WM_capabilities_flag() & WM_CAPABILITY_MULTIMONITOR_PLACEMENT;
if (bounds_valid && mm_placement) {
mx = int(stored_bounds->xmin * UI_SCALE_FAC);
my = int(stored_bounds->ymin * UI_SCALE_FAC);
}
const rcti window_rect = {
/*xmin*/ mx,
/*xmax*/ mx + sizex,
@@ -164,7 +174,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
true,
false,
true,
WIN_ALIGN_LOCATION_CENTER,
WIN_ALIGN_ABSOLUTE,
nullptr,
nullptr) == nullptr)
{

View File

@@ -1891,26 +1891,12 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const
return static_cast<ScrArea *>(screen->areabase.first);
}
ScrArea *ED_screen_temp_space_open(bContext *C,
const char *title,
const rcti *rect_unscaled,
eSpace_Type space_type,
int display_type,
bool dialog)
ScrArea *ED_screen_temp_space_open(
bContext *C, const char *title, eSpace_Type space_type, int display_type, bool dialog)
{
switch (display_type) {
case USER_TEMP_SPACE_DISPLAY_WINDOW:
if (WM_window_open(C,
title,
rect_unscaled,
int(space_type),
false,
dialog,
true,
WIN_ALIGN_LOCATION_CENTER,
nullptr,
nullptr))
{
if (WM_window_open_temp(C, title, space_type, dialog)) {
return CTX_wm_area(C);
}
break;

View File

@@ -1541,8 +1541,11 @@ static void area_dupli_fn(bScreen * /*screen*/, ScrArea *area, void *user_data)
/* operator callback */
static bool area_dupli_open(bContext *C, ScrArea *area, const blender::int2 position)
{
const rcti window_rect = {
position.x, position.x + area->winx, position.y, position.y + area->winy};
const wmWindow *win = CTX_wm_window(C);
const rcti window_rect = {win->posx + position.x,
win->posx + position.x + area->winx,
win->posy + position.y,
win->posy + position.y + area->winy};
/* Create new window. No need to set space_type since it will be copied over. */
wmWindow *newwin = WM_window_open(C,
@@ -6236,12 +6239,6 @@ static void SCREEN_OT_back_to_previous(wmOperatorType *ot)
static wmOperatorStatus userpref_show_exec(bContext *C, wmOperator *op)
{
wmWindow *win_cur = CTX_wm_window(C);
/* Use eventstate, not event from _invoke, so this can be called through exec(). */
const wmEvent *event = win_cur->eventstate;
int sizex = (680 + UI_NAVIGATION_REGION_WIDTH) * UI_SCALE_FAC;
int sizey = 520 * UI_SCALE_FAC;
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "section");
if (prop && RNA_property_is_set(op->ptr, prop)) {
/* Set active section via RNA, so it can fail properly. */
@@ -6253,19 +6250,11 @@ static wmOperatorStatus userpref_show_exec(bContext *C, wmOperator *op)
RNA_property_update(C, &pref_ptr, active_section_prop);
}
const rcti window_rect = {
/*xmin*/ event->xy[0],
/*xmax*/ event->xy[0] + sizex,
/*ymin*/ event->xy[1],
/*ymax*/ event->xy[1] + sizey,
};
/* changes context! */
if (ScrArea *area = ED_screen_temp_space_open(
C, nullptr, &window_rect, SPACE_USERPREF, U.preferences_display_type, false))
{
if (WM_window_open_temp(C, nullptr, SPACE_USERPREF, false)) {
/* The header only contains the editor switcher and looks empty.
* So hiding in the temp window makes sense. */
ScrArea *area = CTX_wm_area(C);
ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
region_header->flag |= RGN_FLAG_HIDDEN;
@@ -6324,13 +6313,6 @@ static void SCREEN_OT_userpref_show(wmOperatorType *ot)
static wmOperatorStatus drivers_editor_show_exec(bContext *C, wmOperator *op)
{
wmWindow *win_cur = CTX_wm_window(C);
/* Use eventstate, not event from _invoke, so this can be called through exec(). */
const wmEvent *event = win_cur->eventstate;
int sizex = 900 * UI_SCALE_FAC;
int sizey = 580 * UI_SCALE_FAC;
/* Get active property to show driver for
* - Need to grab it first, or else this info disappears
* after we've created the window
@@ -6340,25 +6322,8 @@ static wmOperatorStatus drivers_editor_show_exec(bContext *C, wmOperator *op)
PropertyRNA *prop;
uiBut *but = UI_context_active_but_prop_get(C, &ptr, &prop, &index);
const rcti window_rect = {
/*xmin*/ event->xy[0],
/*xmax*/ event->xy[0] + sizex,
/*ymin*/ event->xy[1],
/*ymax*/ event->xy[1] + sizey,
};
/* changes context! */
if (WM_window_open(C,
IFACE_("Blender Drivers Editor"),
&window_rect,
SPACE_GRAPH,
false,
false,
true,
WIN_ALIGN_LOCATION_CENTER,
nullptr,
nullptr) != nullptr)
{
if (WM_window_open_temp(C, IFACE_("Blender Drivers Editor"), SPACE_GRAPH, false)) {
ED_drivers_editor_init(C, CTX_wm_area(C));
/* activate driver F-Curve for the property under the cursor */
@@ -6414,34 +6379,8 @@ static void SCREEN_OT_drivers_editor_show(wmOperatorType *ot)
static wmOperatorStatus info_log_show_exec(bContext *C, wmOperator *op)
{
wmWindow *win_cur = CTX_wm_window(C);
/* Use eventstate, not event from _invoke, so this can be called through exec(). */
const wmEvent *event = win_cur->eventstate;
const int shift_y = 480;
const int mx = event->xy[0];
const int my = event->xy[1] + shift_y;
int sizex = 900 * UI_SCALE_FAC;
int sizey = 580 * UI_SCALE_FAC;
const rcti window_rect = {
/*xmin*/ mx,
/*xmax*/ mx + sizex,
/*ymin*/ my,
/*ymax*/ my + sizey,
};
/* changes context! */
if (WM_window_open(C,
IFACE_("Blender Info Log"),
&window_rect,
SPACE_INFO,
false,
false,
true,
WIN_ALIGN_LOCATION_CENTER,
nullptr,
nullptr) != nullptr)
{
if (WM_window_open_temp(C, IFACE_("Blender Info Log"), SPACE_INFO, false)) {
return OPERATOR_FINISHED;
}
BKE_report(op->reports, RPT_ERROR, "Failed to open window!");

View File

@@ -685,9 +685,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile)
}
}
void ED_fileselect_params_to_userdef(SpaceFile *sfile,
const int temp_win_size[2],
const bool is_maximized)
void ED_fileselect_params_to_userdef(SpaceFile *sfile)
{
FileSelectParams *params = ED_fileselect_get_active_params(sfile);
UserDef_FileSpaceData *sfile_udata_new = &U.file_space_data;
@@ -711,11 +709,6 @@ void ED_fileselect_params_to_userdef(SpaceFile *sfile,
(params->flag & FILE_SORT_INVERT);
}
if (temp_win_size && !is_maximized) {
sfile_udata_new->temp_win_sizex = temp_win_size[0];
sfile_udata_new->temp_win_sizey = temp_win_size[1];
}
/* Tag preferences as dirty if something has changed. */
if (memcmp(sfile_udata_new, &sfile_udata_old, sizeof(sfile_udata_old)) != 0) {
U.runtime.is_dirty = true;
@@ -1327,21 +1320,7 @@ void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
return;
}
if (sfile->op) {
wmWindow *temp_win = (wm->runtime->winactive &&
WM_window_is_temp_screen(wm->runtime->winactive)) ?
wm->runtime->winactive :
nullptr;
if (temp_win) {
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(temp_win, win_size, &is_maximized);
ED_fileselect_params_to_userdef(sfile, win_size, is_maximized);
}
else {
ED_fileselect_params_to_userdef(sfile, nullptr, false);
}
ED_fileselect_params_to_userdef(sfile);
WM_event_fileselect_event(wm, sfile->op, EVT_FILESELECT_EXTERNAL_CANCEL);
sfile->op = nullptr;
}

View File

@@ -2495,28 +2495,9 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot)
static wmOperatorStatus outliner_orphans_manage_invoke(bContext *C,
wmOperator * /*op*/,
const wmEvent *event)
const wmEvent * /*event*/)
{
const int sizex = int(450.0f * UI_SCALE_FAC);
const int sizey = int(450.0f * UI_SCALE_FAC);
const rcti window_rect = {
/*xmin*/ event->xy[0],
/*xmax*/ event->xy[0] + sizex,
/*ymin*/ event->xy[1],
/*ymax*/ event->xy[1] + sizey,
};
if (WM_window_open(C,
IFACE_("Manage Unused Data"),
&window_rect,
SPACE_OUTLINER,
false,
false,
true,
WIN_ALIGN_LOCATION_CENTER,
nullptr,
nullptr) != nullptr)
{
if (WM_window_open_temp(C, IFACE_("Manage Unused Data"), SPACE_OUTLINER, false)) {
SpaceOutliner *soutline = CTX_wm_space_outliner(C);
soutline->outlinevis = SO_ID_ORPHANS;
return OPERATOR_FINISHED;

View File

@@ -8,6 +8,8 @@
#pragma once
#include "BLI_rect.h"
#include "DNA_ID.h"
#include "DNA_colorband_types.h"
#include "DNA_listBase.h"
@@ -194,12 +196,17 @@ typedef struct UserDef_FileSpaceData {
int flag; /* FileSelectParams.flag */
int _pad0;
uint64_t filter_id; /* FileSelectParams.filter_id */
/** Info used when creating the file browser in a temporary window. */
int temp_win_sizex;
int temp_win_sizey;
} UserDef_FileSpaceData;
typedef struct UserDef_TempWinBounds {
rctf file;
rctf userpref;
rctf image;
rctf graph;
rctf info;
rctf outliner;
} UserDef_TempWinBounds;
/**
* Checking experimental members must use the #USER_EXPERIMENTAL_TEST() macro
* unless the #USER_DEVELOPER_UI is known to be enabled.
@@ -614,6 +621,8 @@ typedef struct UserDef {
UserDef_SpaceData space_data;
UserDef_FileSpaceData file_space_data;
UserDef_TempWinBounds stored_bounds;
UserDef_Experimental experimental;
/** Runtime data (keep last). */

View File

@@ -207,6 +207,8 @@ enum eWM_CapabilitiesFlag {
WM_CAPABILITY_CURSOR_RGBA = (1 << 10),
/** Support on demand cursor generation. */
WM_CAPABILITY_CURSOR_GENERATOR = (1 << 11),
/** Ability to save/restore windows among multiple monitors. */
WM_CAPABILITY_MULTIMONITOR_PLACEMENT = (1 << 12),
/** The initial value, indicates the value needs to be set by inspecting GHOST. */
WM_CAPABILITY_INITIALIZED = (1u << 31),
};
@@ -398,6 +400,8 @@ wmWindow *WM_window_open(bContext *C,
void (*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data),
void *area_setup_user_data) ATTR_NONNULL(1, 3);
wmWindow *WM_window_open_temp(bContext *C, const char *title, int space_type, bool dialog);
void WM_window_dpi_set_userdef(const wmWindow *win);
/**
* Return the windows DPI as a scale, bypassing UI scale preference.

View File

@@ -2817,26 +2817,14 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
switch (val) {
case EVT_FILESELECT_FULL_OPEN: {
wmWindow *win = CTX_wm_window(C);
const blender::int2 window_size = WM_window_native_pixel_size(win);
const blender::int2 window_center = window_size / 2;
ScrArea *area = ED_screen_temp_space_open(
C, IFACE_("Blender File View"), SPACE_FILE, U.filebrowser_display_type, true);
if (!area) {
BKE_report(&wm->runtime->reports, RPT_ERROR, "Failed to open file browser!");
return WM_HANDLER_BREAK;
}
const rcti window_rect = {
/*xmin*/ window_center[0],
/*xmax*/ window_center[0] + int(U.file_space_data.temp_win_sizex * UI_SCALE_FAC),
/*ymin*/ window_center[1],
/*ymax*/ window_center[1] + int(U.file_space_data.temp_win_sizey * UI_SCALE_FAC),
};
if (ScrArea *area = ED_screen_temp_space_open(C,
IFACE_("Blender File View"),
&window_rect,
SPACE_FILE,
U.filebrowser_display_type,
true))
{
ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
BLI_assert(area->spacetype == SPACE_FILE);
region_header->flag |= RGN_FLAG_HIDDEN;
@@ -2848,11 +2836,6 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
sfile->op = handler->op;
ED_fileselect_set_params_from_userdef(sfile);
}
else {
BKE_report(&wm->runtime->reports, RPT_ERROR, "Failed to open window!");
return WM_HANDLER_BREAK;
}
action = WM_HANDLER_BREAK;
break;
@@ -2894,11 +2877,7 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
continue;
}
int win_size[2];
bool is_maximized;
ED_fileselect_window_params_get(win, win_size, &is_maximized);
ED_fileselect_params_to_userdef(
static_cast<SpaceFile *>(file_area->spacedata.first), win_size, is_maximized);
ED_fileselect_params_to_userdef(static_cast<SpaceFile *>(file_area->spacedata.first));
if (BLI_listbase_is_single(&file_area->spacedata)) {
BLI_assert(root_win != win);
@@ -2930,8 +2909,7 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
}
if (!temp_win && ctx_area->full) {
ED_fileselect_params_to_userdef(
static_cast<SpaceFile *>(ctx_area->spacedata.first), nullptr, false);
ED_fileselect_params_to_userdef(static_cast<SpaceFile *>(ctx_area->spacedata.first));
ED_screen_full_prevspace(C, ctx_area);
}
}

View File

@@ -447,8 +447,51 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/** \name Window Close
* \{ */
static rctf *stored_window_bounds(eSpace_Type space_type)
{
if (space_type == SPACE_IMAGE) {
return &U.stored_bounds.image;
}
if (space_type == SPACE_USERPREF) {
return &U.stored_bounds.userpref;
}
if (space_type == SPACE_GRAPH) {
return &U.stored_bounds.graph;
}
if (space_type == SPACE_INFO) {
return &U.stored_bounds.info;
}
if (space_type == SPACE_OUTLINER) {
return &U.stored_bounds.outliner;
}
if (space_type == SPACE_FILE) {
return &U.stored_bounds.file;
}
return nullptr;
}
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
bScreen *screen = WM_window_get_active_screen(win);
if (screen->temp && BLI_listbase_is_single(&screen->areabase) && !WM_window_is_maximized(win)) {
ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
rctf *stored_bounds = stored_window_bounds(eSpace_Type(area->spacetype));
if (stored_bounds) {
/* Get DPI and scale from parent window, if there is one. */
WM_window_dpi_set_userdef(win->parent ? win->parent : win);
const float f = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
stored_bounds->xmin = float(win->posx) * f / UI_SCALE_FAC;
stored_bounds->xmax = stored_bounds->xmin + float(win->sizex) * f / UI_SCALE_FAC;
stored_bounds->ymin = float(win->posy) * f / UI_SCALE_FAC;
stored_bounds->ymax = stored_bounds->ymin + float(win->sizey) * f / UI_SCALE_FAC;
/* Tag user preferences as dirty. */
U.runtime.is_dirty = true;
}
}
wmWindow *win_other;
/* First check if there is another main window remaining. */
@@ -472,7 +515,6 @@ void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
}
}
bScreen *screen = WM_window_get_active_screen(win);
WorkSpace *workspace = WM_window_get_active_workspace(win);
WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
@@ -1148,23 +1190,23 @@ wmWindow *WM_window_open(bContext *C,
const float native_pixel_size = GHOST_GetNativePixelSize(
static_cast<GHOST_WindowHandle>(win_prev->ghostwin));
/* Convert to native OS window coordinates. */
rect.xmin = win_prev->posx + (x / native_pixel_size);
rect.ymin = win_prev->posy + (y / native_pixel_size);
rect.xmin = x / native_pixel_size;
rect.ymin = y / native_pixel_size;
sizex /= native_pixel_size;
sizey /= native_pixel_size;
if (alignment == WIN_ALIGN_LOCATION_CENTER) {
/* Window centered around x,y location. */
rect.xmin -= sizex / 2;
rect.ymin -= sizey / 2;
rect.xmin += win_prev->posx - (sizex / 2);
rect.ymin += win_prev->posy - (sizey / 2);
}
else if (alignment == WIN_ALIGN_PARENT_CENTER) {
/* Centered within parent. X,Y as offsets from there. */
rect.xmin += (win_prev->sizex - sizex) / 2;
rect.ymin += (win_prev->sizey - sizey) / 2;
rect.xmin += win_prev->posx + ((win_prev->sizex - sizex) / 2);
rect.ymin += win_prev->posy + ((win_prev->sizey - sizey) / 2);
}
else {
/* Positioned absolutely within parent bounds. */
else if (alignment == WIN_ALIGN_ABSOLUTE) {
/* Positioned absolutely in desktop coordinates. */
}
rect.xmax = rect.xmin + sizex;
@@ -1282,6 +1324,43 @@ wmWindow *WM_window_open(bContext *C,
return nullptr;
}
wmWindow *WM_window_open_temp(bContext *C, const char *title, int space_type, bool dialog)
{
rcti rect;
WM_window_dpi_set_userdef(CTX_wm_window(C));
eWindowAlignment align;
rctf *stored_bounds = stored_window_bounds(eSpace_Type(space_type));
const bool bounds_valid = (stored_bounds && (BLI_rctf_size_x(stored_bounds) > 150.0f) &&
(BLI_rctf_size_y(stored_bounds) > 100.0f));
const bool mm_placement = WM_capabilities_flag() & WM_CAPABILITY_MULTIMONITOR_PLACEMENT;
if (bounds_valid && mm_placement) {
rect.xmin = (int)(stored_bounds->xmin * UI_SCALE_FAC);
rect.ymin = (int)(stored_bounds->ymin * UI_SCALE_FAC);
rect.xmax = (int)(stored_bounds->xmax * UI_SCALE_FAC);
rect.ymax = (int)(stored_bounds->ymax * UI_SCALE_FAC);
align = WIN_ALIGN_ABSOLUTE;
}
else {
wmWindow *win_cur = CTX_wm_window(C);
const int width = int((bounds_valid ? BLI_rctf_size_x(stored_bounds) : 800.0f) * UI_SCALE_FAC);
const int height = int((bounds_valid ? BLI_rctf_size_y(stored_bounds) : 600.0f) *
UI_SCALE_FAC);
/* Use eventstate, not event from _invoke, so this can be called through exec(). */
const wmEvent *event = win_cur->eventstate;
rect.xmin = event->xy[0];
rect.ymin = event->xy[1];
rect.xmax = event->xy[0] + width;
rect.ymax = event->xy[1] + height;
align = WIN_ALIGN_LOCATION_CENTER;
}
wmWindow *win = WM_window_open(
C, title, &rect, space_type, false, dialog, true, align, nullptr, nullptr);
return win;
}
/** \} */
/* -------------------------------------------------------------------- */
@@ -2242,6 +2321,9 @@ eWM_CapabilitiesFlag WM_capabilities_flag()
if (ghost_flag & GHOST_kCapabilityCursorGenerator) {
flag |= WM_CAPABILITY_CURSOR_GENERATOR;
}
if (ghost_flag & GHOST_kCapabilityMultiMonitorPlacement) {
flag |= WM_CAPABILITY_MULTIMONITOR_PLACEMENT;
}
return flag;
}