WIP: UI: Save Temp Window Sizes & Positions #104727

Draft
Harley Acheson wants to merge 2 commits from Harley/blender:WindowPosSize into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
10 changed files with 139 additions and 111 deletions

View File

@ -213,17 +213,27 @@ const UserDef U_default = {
.section_active = USER_SECTION_INTERFACE,
},
.file_space_data =
{
.display_type = FILE_VERTICALDISPLAY,
.thumbnail_size = 96,
.sort_type = FILE_SORT_ALPHA,
.details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME,
.flag = FILE_HIDE_DOT,
.filter_id = FILTER_ID_ALL,
.file_space_data = {.display_type = FILE_VERTICALDISPLAY,
.thumbnail_size = 96,
.sort_type = FILE_SORT_ALPHA,
.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,
.file_winstate =
{
.posx = 0,
.posy = 0,
.sizex = 1060,
.sizey = 600,
},
.file_winstate =
{
.posx = 0,
.posy = 0,
.sizex = 560,
.sizey = 520,
},
.sequencer_disk_cache_dir = "",

View File

@ -108,9 +108,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);
@ -170,8 +168,6 @@ void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, bool deferred)
void ED_fileselect_deselect_all(SpaceFile *sfile);
void ED_fileselect_activate_by_relpath(SpaceFile *sfile, const char *relative_path);
void ED_fileselect_window_params_get(const wmWindow *win, int r_win_size[2], bool *r_is_maximized);
/**
* Return the File Browser area in which \a file_operator is active.
*/

View File

@ -1459,11 +1459,12 @@ static int area_dupli_invoke(bContext *C, wmOperator *op, const wmEvent *event)
area = sad->sa1;
}
wmWindow *win = CTX_wm_window(C);
const rcti window_rect = {
/*xmin*/ area->totrct.xmin,
/*xmax*/ area->totrct.xmin + area->winx,
/*ymin*/ area->totrct.ymin,
/*ymax*/ area->totrct.ymin + area->winy,
/*xmin*/ win->posx + area->totrct.xmin,
/*xmax*/ win->posx + area->totrct.xmin + area->winx,
/*ymin*/ win->posy + area->totrct.ymin,
/*ymax*/ win->posy + area->totrct.ymin + area->winy,
};
/* Create new window. No need to set space_type since it will be copied over. */
@ -5200,12 +5201,6 @@ static void SCREEN_OT_back_to_previous(wmOperatorType *ot)
static int 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 = (500 + 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. */
@ -5217,24 +5212,14 @@ static int 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 (WM_window_open(C,
IFACE_("Blender Preferences"),
&window_rect,
SPACE_USERPREF,
false,
false,
true,
WIN_ALIGN_LOCATION_CENTER,
nullptr,
nullptr) != nullptr)
if (WM_window_open_temp(C,
IFACE_("Blender Preferences"),
&U.preferences_winstate,
500 + UI_NAVIGATION_REGION_WIDTH,
520,
SPACE_USERPREF,
false) != nullptr)
{
/* The header only contains the editor switcher and looks empty.
* So hiding in the temp window makes sense. */

View File

@ -623,17 +623,6 @@ void ED_fileselect_deselect_all(SpaceFile *sfile)
* may also be remembered, but only conditionally. */
#define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT)
void ED_fileselect_window_params_get(const wmWindow *win, int r_win_size[2], bool *r_is_maximized)
{
/* Get DPI/pixel-size independent size to be stored in preferences. */
WM_window_set_dpi(win); /* Ensure the DPI is taken from the right window. */
r_win_size[0] = WM_window_pixels_x(win) / UI_SCALE_FAC;
r_win_size[1] = WM_window_pixels_y(win) / UI_SCALE_FAC;
*r_is_maximized = WM_window_is_maximized(win);
}
static bool file_select_use_default_display_type(const SpaceFile *sfile)
{
PropertyRNA *prop;
@ -680,9 +669,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;
@ -706,11 +693,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;
@ -1302,17 +1284,7 @@ void ED_fileselect_exit(wmWindowManager *wm, SpaceFile *sfile)
wmWindow *temp_win = (wm->winactive && WM_window_is_temp_screen(wm->winactive)) ?
wm->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

@ -684,12 +684,19 @@ 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;
/**
* Storage for temp window position and size. Needs to
* use floats (divided by UI_DPI_FAC) to avoid drifting.
*/
typedef struct UserDef_WinState {
float posx;
float posy;
float sizex;
float sizey;
} UserDef_WinState;
typedef struct UserDef_Experimental {
/* Debug options, always available. */
char use_undo_legacy;
@ -1040,6 +1047,9 @@ typedef struct UserDef {
UserDef_SpaceData space_data;
UserDef_FileSpaceData file_space_data;
UserDef_WinState file_winstate;
UserDef_WinState preferences_winstate;
UserDef_Experimental experimental;
/** Runtime data (keep last). */
@ -1478,7 +1488,8 @@ typedef enum eUserpref_RenderDisplayType {
USER_RENDER_DISPLAY_NONE = 0,
USER_RENDER_DISPLAY_SCREEN = 1,
USER_RENDER_DISPLAY_AREA = 2,
USER_RENDER_DISPLAY_WINDOW = 3
USER_RENDER_DISPLAY_WINDOW = 3,
USER_RENDER_DISPLAY_WINDOW_SAVED = 4
} eUserpref_RenderDisplayType;
typedef enum eUserpref_TempSpaceDisplayType {

View File

@ -392,6 +392,11 @@ typedef struct wmWindow {
/** Private runtime info to show text in the status bar. */
void *cursor_keymap_status;
/* Optional pointer to a UserDef_WinState used to save/restore size and position. */
struct UserDef_WinState *savestate;
void *_pad2;
/**
* The time when the key is pressed in milliseconds (see #GHOST_GetEventTime).
* Used to detect double-click events.

View File

@ -462,6 +462,8 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(bTheme),
SDNA_DEFAULT_DECL_EX(UserDef_SpaceData, UserDef.space_data),
SDNA_DEFAULT_DECL_EX(UserDef_FileSpaceData, UserDef.file_space_data),
SDNA_DEFAULT_DECL_EX(UserDef_WinState, UserDef.file_winstate),
SDNA_DEFAULT_DECL_EX(UserDef_WinState, UserDef.preferences_winstate),
SDNA_DEFAULT_DECL_EX(WalkNavigation, UserDef.walk_navigation),
SDNA_DEFAULT_DECL(bUserAssetLibrary),
SDNA_DEFAULT_DECL(bUserExtensionRepo),

View File

@ -349,6 +349,14 @@ 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, 2, 3);
struct wmWindow *WM_window_open_temp(struct bContext *C,
const char *title,
struct UserDef_WinState *state,
int def_sizex,
int def_sizey,
int space_type,
bool dialog);
void WM_window_set_dpi(const wmWindow *win);
bool WM_stereo3d_enabled(wmWindow *win, bool only_fullscreen_test);

View File

@ -2659,26 +2659,11 @@ static eHandlerActionFlag wm_handler_fileselect_do(bContext *C,
switch (val) {
case EVT_FILESELECT_FULL_OPEN: {
wmWindow *win = CTX_wm_window(C);
const int window_center[2] = {
WM_window_pixels_x(win) / 2,
WM_window_pixels_y(win) / 2,
};
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))
if (WM_window_open_temp(
C, IFACE_("Blender File View"), &U.file_winstate, 1060, 600, SPACE_FILE, true) !=
nullptr)
{
ScrArea *area = CTX_wm_area(C);
ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER);
BLI_assert(area->spacetype == SPACE_FILE);
@ -2738,11 +2723,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);
@ -2774,8 +2755,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

@ -428,6 +428,27 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
if (win->savestate && !WM_window_is_maximized(win)) {
/* Get DPI and scale from parent window, if there is one. */
WM_window_set_dpi(win->parent ? win->parent : win);
float f = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
float sizex = (float)win->sizex * f / UI_SCALE_FAC;
float sizey = (float)win->sizey * f / UI_SCALE_FAC;
float posx = (float)win->posx * f / UI_SCALE_FAC;
float posy = (float)win->posy * f / UI_SCALE_FAC;
if (sizex != win->savestate->sizex || sizey != win->savestate->sizey ||
posx != win->savestate->posx || posy != win->savestate->posy)
{
win->savestate->sizex = sizex;
win->savestate->sizey = sizey;
win->savestate->posx = posx;
win->savestate->posy = posy;
/* Tag user preferences as dirty. */
U.runtime.is_dirty = true;
}
}
wmWindow *win_other;
/* First check if there is another main window remaining. */
@ -960,23 +981,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;
@ -1094,6 +1115,44 @@ wmWindow *WM_window_open(bContext *C,
return nullptr;
}
wmWindow *WM_window_open_temp(struct bContext *C,
const char *title,
UserDef_WinState *state,
int def_sizex,
int def_sizey,
int space_type,
bool dialog)
{
rcti rect;
int posx, posy, sizex, sizey;
eWindowAlignment align;
WM_window_set_dpi(CTX_wm_window(C));
if (state && state->sizex != 0.0f) {
rect.xmin = (int)(state->posx * UI_SCALE_FAC);
rect.ymin = (int)(state->posy * UI_SCALE_FAC);
rect.xmax = rect.xmin + (int)(state->sizex * UI_SCALE_FAC);
rect.ymax = rect.ymin + (int)(state->sizey * UI_SCALE_FAC);
align = WIN_ALIGN_ABSOLUTE;
}
else {
rect.xmin = 0;
rect.ymin = 0;
rect.xmax = def_sizex * UI_SCALE_FAC;
rect.ymax = def_sizey * UI_SCALE_FAC;
align = WIN_ALIGN_LOCATION_CENTER;
}
wmWindow *win = WM_window_open(
C, title, &rect, space_type, false, dialog, true, align, nullptr, nullptr);
win->savestate = state;
return win;
}
/** \} */
/* -------------------------------------------------------------------- */