This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/render/render_view.c

375 lines
10 KiB
C
Raw Normal View History

/*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2008 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup edrend
*/
#include <stddef.h>
#include <string.h>
#include "BLI_listbase.h"
#include "BLI_utildefines.h"
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_image.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_screen.h"
#include "BLT_translation.h"
#include "WM_api.h"
#include "WM_types.h"
#include "ED_screen.h"
#include "UI_interface.h"
#include "wm_window.h"
#include "render_intern.h"
/*********************** utilities for finding areas *************************/
/* returns biggest area that is not uv/image editor. Note that it uses buttons */
/* window as the last possible alternative. */
/* would use BKE_screen_find_big_area(...) but this is too specific */
static ScrArea *biggest_non_image_area(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *area, *big = NULL;
int size, maxsize = 0, bwmaxsize = 0;
short foundwin = 0;
for (area = screen->areabase.first; area; area = area->next) {
if (area->winx > 30 && area->winy > 30) {
size = area->winx * area->winy;
if (!area->full && area->spacetype == SPACE_PROPERTIES) {
if (foundwin == 0 && size > bwmaxsize) {
bwmaxsize = size;
big = area;
}
}
else if (area->spacetype != SPACE_IMAGE && size > maxsize) {
maxsize = size;
big = area;
foundwin = 1;
}
}
}
return big;
}
static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win)
{
wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = NULL;
SpaceImage *sima;
/* find an imagewindow showing render result */
for (*win = wm->windows.first; *win; *win = (*win)->next) {
if (WM_window_get_active_scene(*win) == scene) {
const bScreen *screen = WM_window_get_active_screen(*win);
for (area = screen->areabase.first; area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
sima = area->spacedata.first;
2019-04-22 09:19:45 +10:00
if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) {
break;
2019-04-22 09:19:45 +10:00
}
}
}
if (area) {
break;
2019-04-22 09:19:45 +10:00
}
}
}
return area;
}
static ScrArea *find_area_image_empty(bContext *C)
{
bScreen *screen = CTX_wm_screen(C);
ScrArea *area;
SpaceImage *sima;
/* find an imagewindow showing render result */
for (area = screen->areabase.first; area; area = area->next) {
if (area->spacetype == SPACE_IMAGE) {
sima = area->spacedata.first;
if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
2019-04-22 09:19:45 +10:00
}
}
}
return area;
}
/********************** open image editor for render *************************/
/* new window uses x,y to set position */
ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
wmWindow *win = NULL;
ScrArea *area = NULL;
SpaceImage *sima;
bool area_was_image = false;
if (U.render_display_type == USER_RENDER_DISPLAY_NONE) {
return NULL;
2019-04-22 09:19:45 +10:00
}
if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) {
int sizex = 30 * UI_DPI_FAC + (scene->r.xsch * scene->r.size) / 100;
int sizey = 60 * UI_DPI_FAC + (scene->r.ysch * scene->r.size) / 100;
/* arbitrary... miniature image window views don't make much sense */
2019-04-22 09:19:45 +10:00
if (sizex < 320) {
sizex = 320;
2019-04-22 09:19:45 +10:00
}
if (sizey < 256) {
sizey = 256;
2019-04-22 09:19:45 +10:00
}
/* changes context! */
UI: Register File Browser as Child/Dialog-Window for the OS For many users, this will make the File Browser window behave more like what they would expect. It addresses the issue of the File Browser becoming hidden behind the main window by clicking anywhere in the latter. It communicates the interruptive, but temporary nature of the operation a bit better. Further, on tiling window managers the File Browser now opens as floating by default, like in other applications. Note that this also makes sure the File Browser is always opened as separate window, so it doesn't re-use the Preferences, or any other temporary window anymore. This seems to have been a common annoyance. More concretely, this makes the File Browser window behave as follows: * Stays on top of its parent Blender window, but not on top of non-Blender windows. * Minimizes with its parent window * Can be moved independently * Doesn't add an own item in task bars * Doesn't block other Blender windows (we may want to have this though) * Opens as floating window for tiling window managers (e.g. i3wm/Sway) Further notes: * When opening a file browser from the Preference window (or any temporary window), the main window, as the file browsers parent is moved on top of the Preferences, which makes it seem like the Preferences were closed. This is the general issue of bad secondary window handling as window activation changes. I made it so that the window is moved back once the file browser is closed. This behavior is confusing and would be nice to avoid. It's a separate issue though. * On most window managers on Linux the temporary window can not be minimized and maximized, they disable that for dialog windows. * On Windows and macOS, only minimizing is disabled, as there is no decent way yet to restore a window if it's not shown in the taskbar. Reviewed By: Brecht van Lommel, Campbell Barton, William Reynish Edits and macOS implementation by Brecht. Differential Revision: https://developer.blender.org/D5810 Part of T69652.
2019-10-03 16:59:49 +02:00
if (WM_window_open_temp(
C, IFACE_("Blender Render"), mx, my, sizex, sizey, SPACE_IMAGE, false) == NULL) {
BKE_report(reports, RPT_ERROR, "Failed to open window!");
return NULL;
}
area = CTX_wm_area(C);
if (BLI_listbase_is_single(&area->spacedata) == false) {
sima = area->spacedata.first;
sima->flag |= SI_PREVSPACE;
}
}
else if (U.render_display_type == USER_RENDER_DISPLAY_SCREEN) {
area = CTX_wm_area(C);
/* if the active screen is already in fullscreen mode, skip this and
* unset the area, so that the fullscreen area is just changed later */
if (area && area->full) {
area = NULL;
}
else {
if (area && area->spacetype == SPACE_IMAGE) {
area_was_image = true;
2019-04-22 09:19:45 +10:00
}
/* this function returns with changed context */
area = ED_screen_full_newspace(C, area, SPACE_IMAGE);
}
}
if (!area) {
area = find_area_showing_r_result(C, scene, &win);
if (area == NULL) {
area = find_area_image_empty(C);
2019-04-22 09:19:45 +10:00
}
/* if area found in other window, we make that one show in front */
2019-04-22 09:19:45 +10:00
if (win && win != CTX_wm_window(C)) {
wm_window_raise(win);
2019-04-22 09:19:45 +10:00
}
if (area == NULL) {
/* find largest open non-image area */
area = biggest_non_image_area(C);
if (area) {
ED_area_newspace(C, area, SPACE_IMAGE, true);
sima = area->spacedata.first;
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
/* we already had a fullscreen here -> mark new space as a stacked fullscreen */
if (area->full) {
area->flag |= AREA_FLAG_STACKED_FULLSCREEN;
}
}
else {
/* use any area of decent size */
area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0);
if (area->spacetype != SPACE_IMAGE) {
// XXX newspace(area, SPACE_IMAGE);
sima = area->spacedata.first;
/* makes ESC go back to prev space */
sima->flag |= SI_PREVSPACE;
}
}
}
}
sima = area->spacedata.first;
sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
sima->image = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
2019-08-18 04:11:50 +10:00
/* If we're rendering to full screen, set appropriate hints on image editor
* so it can restore properly on pressing escape. */
if (area->full) {
sima->flag |= SI_FULLWINDOW;
/* Tell the image editor to revert to previous space in space list on close
* _only_ if it wasn't already an image editor when the render was invoked */
2019-04-22 09:19:45 +10:00
if (area_was_image == 0) {
sima->flag |= SI_PREVSPACE;
2019-04-22 09:19:45 +10:00
}
else {
/* Leave it alone so the image editor will just go back from
* full screen to the original tiled setup */
}
}
if ((sima->flag & SI_PREVSPACE) && sima->next) {
SpaceLink *old_sl = sima->next;
old_sl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE;
}
return area;
}
/*************************** cancel render viewer **********************/
static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win = CTX_wm_window(C);
ScrArea *area = CTX_wm_area(C);
SpaceImage *sima = area->spacedata.first;
/* ensure image editor fullscreen and area fullscreen states are in sync */
if ((sima->flag & SI_FULLWINDOW) && !area->full) {
sima->flag &= ~SI_FULLWINDOW;
}
/* determine if render already shows */
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
ED_screen_full_prevspace(C, area);
}
else {
ED_area_prevspace(C, area);
}
return OPERATOR_FINISHED;
}
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED);
return OPERATOR_FINISHED;
}
if (WM_window_is_temp_screen(win)) {
wm_window_close(C, CTX_wm_manager(C), win);
return OPERATOR_FINISHED;
}
return OPERATOR_PASS_THROUGH;
}
void RENDER_OT_view_cancel(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Cancel Render View";
ot->description = "Cancel show render view";
ot->idname = "RENDER_OT_view_cancel";
/* api callbacks */
ot->exec = render_view_cancel_exec;
ot->poll = ED_operator_image_active;
}
/************************* show render viewer *****************/
static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
wmWindow *wincur = CTX_wm_window(C);
/* test if we have currently a temp screen active */
if (WM_window_is_temp_screen(wincur)) {
wm_window_lower(wincur);
}
else {
wmWindow *win, *winshow;
ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow);
/* is there another window on current scene showing result? */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) {
const bScreen *screen = WM_window_get_active_screen(win);
if ((WM_window_is_temp_screen(win) &&
((ScrArea *)screen->areabase.first)->spacetype == SPACE_IMAGE) ||
(win == winshow && winshow != wincur)) {
wm_window_raise(win);
return OPERATOR_FINISHED;
}
}
/* determine if render already shows */
if (area) {
/* but don't close it when rendering */
if (G.is_rendering == false) {
SpaceImage *sima = area->spacedata.first;
if (sima->flag & SI_PREVSPACE) {
sima->flag &= ~SI_PREVSPACE;
if (sima->flag & SI_FULLWINDOW) {
sima->flag &= ~SI_FULLWINDOW;
ED_screen_full_prevspace(C, area);
}
else {
ED_area_prevspace(C, area);
}
}
}
}
else {
render_view_open(C, event->x, event->y, op->reports);
}
}
return OPERATOR_FINISHED;
}
void RENDER_OT_view_show(struct wmOperatorType *ot)
{
/* identifiers */
ot->name = "Show/Hide Render View";
ot->description = "Toggle show render view";
ot->idname = "RENDER_OT_view_show";
/* api callbacks */
ot->invoke = render_view_show_invoke;
ot->poll = ED_operator_screenactive;
}