2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2009-01-06 14:42:54 +00:00
|
|
|
* 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
|
2018-06-01 18:19:39 +02:00
|
|
|
* of the License, or (at your option) any later version.
|
2009-01-06 14:42:54 +00:00
|
|
|
*
|
|
|
|
* 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,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2009-01-06 14:42:54 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
|
|
|
* \ingroup spfile
|
2011-02-27 20:29:51 +00:00
|
|
|
*/
|
|
|
|
|
2013-01-10 16:37:48 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2019-03-05 21:01:45 +01:00
|
|
|
|
|
|
|
#include "BLI_blenlib.h"
|
2015-02-11 00:09:45 +01:00
|
|
|
#include "BLI_linklist.h"
|
2019-03-05 21:01:45 +01:00
|
|
|
#include "BLI_math.h"
|
2011-02-27 20:29:51 +00:00
|
|
|
|
2013-11-22 14:35:34 +01:00
|
|
|
#include "BLO_readfile.h"
|
|
|
|
|
2014-11-23 14:37:13 +01:00
|
|
|
#include "BKE_appdir.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
#include "BKE_context.h"
|
|
|
|
#include "BKE_global.h"
|
2010-10-18 06:41:16 +00:00
|
|
|
#include "BKE_main.h"
|
2018-11-07 18:00:24 +01:00
|
|
|
#include "BKE_report.h"
|
|
|
|
#include "BKE_screen.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2012-04-15 07:54:07 +00:00
|
|
|
# include "BLI_winstuff.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "ED_fileselect.h"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "ED_screen.h"
|
2019-03-07 20:33:57 +11:00
|
|
|
#include "ED_select_utils.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
|
2013-11-22 01:35:38 +01:00
|
|
|
#include "UI_interface.h"
|
2019-12-06 13:10:30 -08:00
|
|
|
#include "UI_interface_icons.h"
|
|
|
|
#include "UI_resources.h"
|
2013-11-22 01:35:38 +01:00
|
|
|
|
2009-06-29 20:23:40 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
2009-01-21 19:28:28 +00:00
|
|
|
#include "RNA_access.h"
|
|
|
|
#include "RNA_define.h"
|
2009-01-06 14:42:54 +00:00
|
|
|
|
2009-01-06 16:15:43 +00:00
|
|
|
#include "UI_view2d.h"
|
|
|
|
|
2009-01-21 19:28:28 +00:00
|
|
|
#include "WM_api.h"
|
|
|
|
#include "WM_types.h"
|
|
|
|
|
2009-01-06 14:42:54 +00:00
|
|
|
#include "file_intern.h"
|
|
|
|
#include "filelist.h"
|
|
|
|
#include "fsmenu.h"
|
|
|
|
|
2011-08-05 06:06:15 +00:00
|
|
|
#include <ctype.h>
|
2016-02-03 16:37:02 +11:00
|
|
|
#include <errno.h>
|
2020-03-19 09:33:03 +01:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-01-06 14:42:54 +00:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name File Selection Utilities
|
|
|
|
* \{ */
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
static FileSelection find_file_mouse_rect(SpaceFile *sfile,
|
|
|
|
ARegion *region,
|
|
|
|
const rcti *rect_region)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
FileSelection sel;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
View2D *v2d = ®ion->v2d;
|
2019-04-17 06:17:24 +02:00
|
|
|
rcti rect_view;
|
|
|
|
rctf rect_view_fl;
|
|
|
|
rctf rect_region_fl;
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_rctf_rcti_copy(&rect_region_fl, rect_region);
|
2009-01-21 19:28:28 +00:00
|
|
|
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
/* Okay, manipulating v2d rects here is hacky... */
|
|
|
|
v2d->mask.ymax -= sfile->layout->offset_top;
|
|
|
|
v2d->cur.ymax -= sfile->layout->offset_top;
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl);
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
v2d->mask.ymax += sfile->layout->offset_top;
|
|
|
|
v2d->cur.ymax += sfile->layout->offset_top;
|
2014-04-21 16:47:16 +10:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_rcti_init(&rect_view,
|
|
|
|
(int)(v2d->tot.xmin + rect_view_fl.xmin),
|
|
|
|
(int)(v2d->tot.xmin + rect_view_fl.xmax),
|
|
|
|
(int)(v2d->tot.ymax - rect_view_fl.ymin),
|
|
|
|
(int)(v2d->tot.ymax - rect_view_fl.ymax));
|
2011-03-14 19:56:13 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
sel = ED_fileselect_layout_offset_rect(sfile->layout, &rect_view);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return sel;
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2020-04-03 16:21:24 +11:00
|
|
|
static void file_deselect_all(SpaceFile *sfile, uint flag)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
FileSelection sel;
|
|
|
|
sel.first = 0;
|
|
|
|
sel.last = filelist_files_ensure(sfile->files) - 1;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
filelist_entries_select_index_range_set(sfile->files, &sel, FILE_SEL_REMOVE, flag, CHECK_ALL);
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2017-10-17 13:43:10 +11:00
|
|
|
typedef enum FileSelect {
|
2019-04-17 06:17:24 +02:00
|
|
|
FILE_SELECT_NOTHING = 0,
|
|
|
|
FILE_SELECT_DIR = 1,
|
|
|
|
FILE_SELECT_FILE = 2,
|
2011-03-14 19:56:13 +00:00
|
|
|
} FileSelect;
|
2009-07-26 19:23:07 +00:00
|
|
|
|
2012-06-18 13:01:24 +00:00
|
|
|
static void clamp_to_filelist(int numfiles, FileSelection *sel)
|
2009-09-20 15:02:14 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* box select before the first file */
|
|
|
|
if ((sel->first < 0) && (sel->last >= 0)) {
|
|
|
|
sel->first = 0;
|
|
|
|
}
|
|
|
|
/* don't select if everything is outside filelist */
|
|
|
|
if ((sel->first >= numfiles) && ((sel->last < 0) || (sel->last >= numfiles))) {
|
|
|
|
sel->first = -1;
|
|
|
|
sel->last = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fix if last file invalid */
|
2019-04-22 09:19:45 +10:00
|
|
|
if ((sel->first > 0) && (sel->last < 0)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
sel->last = numfiles - 1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* clamp */
|
|
|
|
if ((sel->first >= numfiles)) {
|
|
|
|
sel->first = numfiles - 1;
|
|
|
|
}
|
|
|
|
if ((sel->last >= numfiles)) {
|
|
|
|
sel->last = numfiles - 1;
|
|
|
|
}
|
2009-09-20 15:02:14 +00:00
|
|
|
}
|
|
|
|
|
2014-04-11 11:25:41 +10:00
|
|
|
static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
int numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
FileSelection sel;
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
sel = find_file_mouse_rect(sfile, region, rect);
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!((sel.first == -1) && (sel.last == -1))) {
|
|
|
|
clamp_to_filelist(numfiles, &sel);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if desired, fill the selection up from the last selected file to the current one */
|
|
|
|
if (fill && (sel.last >= 0) && (sel.last < numfiles)) {
|
|
|
|
int f;
|
|
|
|
/* Try to find a smaller-index selected item. */
|
|
|
|
for (f = sel.last; f >= 0; f--) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
if (f >= 0) {
|
|
|
|
sel.first = f + 1;
|
|
|
|
}
|
|
|
|
/* If none found, try to find a higher-index selected item. */
|
|
|
|
else {
|
|
|
|
for (f = sel.first; f < numfiles; f++) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
break;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
if (f < numfiles) {
|
|
|
|
sel.last = f - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sel;
|
2011-03-14 19:56:13 +00:00
|
|
|
}
|
2009-03-08 13:14:12 +00:00
|
|
|
|
2014-04-11 11:25:41 +10:00
|
|
|
static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen)
|
2011-03-14 19:56:13 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
FileSelect retval = FILE_SELECT_NOTHING;
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
|
|
|
int numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
const FileDirEntry *file;
|
|
|
|
|
|
|
|
/* make the selected file active */
|
|
|
|
if ((selected_idx >= 0) && (selected_idx < numfiles) &&
|
|
|
|
(file = filelist_file(sfile->files, selected_idx))) {
|
|
|
|
params->highlight_file = selected_idx;
|
|
|
|
params->active_file = selected_idx;
|
|
|
|
|
|
|
|
if (file->typeflag & FILE_TYPE_DIR) {
|
|
|
|
const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath);
|
|
|
|
|
|
|
|
if (do_diropen == false) {
|
|
|
|
retval = FILE_SELECT_DIR;
|
|
|
|
}
|
|
|
|
/* the path is too long and we are not going up! */
|
|
|
|
else if (!is_parent_dir && strlen(params->dir) + strlen(file->relpath) >= FILE_MAX) {
|
|
|
|
// XXX error("Path too long, cannot enter this directory");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (is_parent_dir) {
|
|
|
|
/* avoids /../../ */
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_parent_dir(params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
if (params->recursion_level > 1) {
|
|
|
|
/* Disable 'dirtree' recursion when going up in tree. */
|
|
|
|
params->recursion_level = 0;
|
|
|
|
filelist_setrecursion(sfile->files, params->recursion_level);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
strcat(params->dir, file->relpath);
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_slash_ensure(params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ED_file_change_dir(C);
|
|
|
|
retval = FILE_SELECT_DIR;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
retval = FILE_SELECT_FILE;
|
|
|
|
}
|
|
|
|
fileselect_file_set(sfile, selected_idx);
|
|
|
|
}
|
|
|
|
return retval;
|
2011-03-14 19:56:13 +00:00
|
|
|
}
|
|
|
|
|
2015-06-12 04:42:31 +02:00
|
|
|
/**
|
|
|
|
* \warning: loops over all files so better use cautiously
|
|
|
|
*/
|
|
|
|
static bool file_is_any_selected(struct FileList *files)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
const int numfiles = filelist_files_ensure(files);
|
|
|
|
int i;
|
2015-06-12 04:42:31 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* Is any file selected ? */
|
2019-09-08 00:12:26 +10:00
|
|
|
for (i = 0; i < numfiles; i++) {
|
2019-04-17 06:17:24 +02:00
|
|
|
if (filelist_entry_select_index_get(files, i, CHECK_ALL)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2015-06-12 04:42:31 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return false;
|
2015-06-12 04:42:31 +02:00
|
|
|
}
|
|
|
|
|
2015-09-19 03:29:06 +02:00
|
|
|
/**
|
|
|
|
* If \a file is outside viewbounds, this adjusts view to make sure it's inside
|
|
|
|
*/
|
2020-03-06 16:56:42 +01:00
|
|
|
static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, const int file)
|
2015-09-19 03:29:06 +02:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
FileLayout *layout = ED_fileselect_get_layout(sfile, region);
|
|
|
|
rctf *cur = ®ion->v2d.cur;
|
2019-04-17 06:17:24 +02:00
|
|
|
rcti rect;
|
|
|
|
bool changed = true;
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
file_tile_boundbox(region, layout, file, &rect);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* down - also use if tile is higher than viewbounds so view is aligned to file name */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (cur->ymin > rect.ymin || layout->tile_h > region->winy) {
|
2019-04-17 06:17:24 +02:00
|
|
|
cur->ymin = rect.ymin - (2 * layout->tile_border_y);
|
2020-03-06 16:56:42 +01:00
|
|
|
cur->ymax = cur->ymin + region->winy;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
/* up */
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
else if ((cur->ymax - layout->offset_top) < rect.ymax) {
|
|
|
|
cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top;
|
2020-03-06 16:56:42 +01:00
|
|
|
cur->ymin = cur->ymax - region->winy;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
/* left - also use if tile is wider than viewbounds so view is aligned to file name */
|
2020-03-06 16:56:42 +01:00
|
|
|
else if (cur->xmin > rect.xmin || layout->tile_w > region->winx) {
|
2019-04-17 06:17:24 +02:00
|
|
|
cur->xmin = rect.xmin - layout->tile_border_x;
|
2020-03-06 16:56:42 +01:00
|
|
|
cur->xmax = cur->xmin + region->winx;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
/* right */
|
|
|
|
else if (cur->xmax < rect.xmax) {
|
|
|
|
cur->xmax = rect.xmax + (2 * layout->tile_border_x);
|
2020-03-06 16:56:42 +01:00
|
|
|
cur->xmin = cur->xmax - region->winx;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin &&
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
(cur->ymax - layout->offset_top) >= rect.ymax);
|
2019-04-17 06:17:24 +02:00
|
|
|
changed = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (changed) {
|
2020-03-06 16:56:42 +01:00
|
|
|
UI_view2d_curRect_validate(®ion->v2d);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static FileSelect file_select(
|
|
|
|
bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen)
|
|
|
|
{
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
FileSelect retval = FILE_SELECT_NOTHING;
|
|
|
|
FileSelection sel = file_selection_get(C, rect, fill); /* get the selection */
|
|
|
|
const FileCheckType check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS :
|
|
|
|
CHECK_ALL;
|
|
|
|
|
|
|
|
/* flag the files as selected in the filelist */
|
|
|
|
filelist_entries_select_index_range_set(
|
|
|
|
sfile->files, &sel, select, FILE_SEL_SELECTED, check_type);
|
|
|
|
|
|
|
|
/* Don't act on multiple selected files */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (sel.first != sel.last) {
|
2019-04-17 06:17:24 +02:00
|
|
|
select = 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* Do we have a valid selection and are we actually selecting */
|
|
|
|
if ((sel.last >= 0) && (select != FILE_SEL_REMOVE)) {
|
|
|
|
/* Check last selection, if selected, act on the file or dir */
|
|
|
|
if (filelist_entry_select_index_get(sfile->files, sel.last, check_type)) {
|
|
|
|
retval = file_select_do(C, sel.last, do_diropen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (select != FILE_SEL_ADD && !file_is_any_selected(sfile->files)) {
|
|
|
|
sfile->params->active_file = -1;
|
|
|
|
}
|
2020-01-08 16:45:09 +01:00
|
|
|
else if (sel.last >= 0) {
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
const FileLayout *layout = ED_fileselect_get_layout(sfile, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* Adjust view to display selection. Doing iterations for first and last
|
|
|
|
* selected item makes view showing as much of the selection possible.
|
|
|
|
* Not really useful if tiles are (almost) bigger than viewbounds though. */
|
2020-03-06 16:56:42 +01:00
|
|
|
if (((layout->flag & FILE_LAYOUT_HOR) && region->winx > (1.2f * layout->tile_w)) ||
|
|
|
|
((layout->flag & FILE_LAYOUT_VER) && region->winy > (2.0f * layout->tile_h))) {
|
|
|
|
file_ensure_inside_viewbounds(region, sfile, sel.last);
|
|
|
|
file_ensure_inside_viewbounds(region, sfile, sel.first);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* update operator for name change event */
|
|
|
|
file_draw_check(C);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Box Select Operator
|
|
|
|
* \{ */
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
static int file_box_select_find_last_selected(SpaceFile *sfile,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2019-04-17 06:17:24 +02:00
|
|
|
const FileSelection *sel,
|
|
|
|
const int mouse_xy[2])
|
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
FileLayout *layout = ED_fileselect_get_layout(sfile, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
rcti bounds_first, bounds_last;
|
|
|
|
int dist_first, dist_last;
|
|
|
|
float mouseco_view[2];
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
UI_view2d_region_to_view(®ion->v2d, UNPACK2(mouse_xy), &mouseco_view[0], &mouseco_view[1]);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
file_tile_boundbox(region, layout, sel->first, &bounds_first);
|
|
|
|
file_tile_boundbox(region, layout, sel->last, &bounds_last);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* are first and last in the same column (horizontal layout)/row (vertical layout)? */
|
|
|
|
if ((layout->flag & FILE_LAYOUT_HOR && bounds_first.xmin == bounds_last.xmin) ||
|
|
|
|
(layout->flag & FILE_LAYOUT_VER && bounds_first.ymin != bounds_last.ymin)) {
|
|
|
|
/* use vertical distance */
|
|
|
|
const int my_loc = (int)mouseco_view[1];
|
|
|
|
dist_first = BLI_rcti_length_y(&bounds_first, my_loc);
|
|
|
|
dist_last = BLI_rcti_length_y(&bounds_last, my_loc);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* use horizontal distance */
|
|
|
|
const int mx_loc = (int)mouseco_view[0];
|
|
|
|
dist_first = BLI_rcti_length_x(&bounds_first, mx_loc);
|
|
|
|
dist_last = BLI_rcti_length_x(&bounds_last, mx_loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (dist_first < dist_last) ? sel->first : sel->last;
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
}
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
2011-03-20 00:34:08 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
|
|
|
FileSelection sel;
|
|
|
|
rcti rect;
|
2011-03-20 00:34:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
int result;
|
2011-03-20 00:34:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
result = WM_gesture_box_modal(C, op, event);
|
2011-03-20 00:34:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (result == OPERATOR_RUNNING_MODAL) {
|
|
|
|
WM_operator_properties_border_to_rcti(op, &rect);
|
2011-03-20 00:34:08 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_fileselect_layout_isect_rect(sfile->layout, ®ion->v2d, &rect, &rect);
|
2011-03-20 00:34:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
sel = file_selection_get(C, &rect, 0);
|
|
|
|
if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) {
|
|
|
|
int idx;
|
2015-01-04 02:36:42 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
|
|
|
|
filelist_entries_select_index_range_set(
|
|
|
|
sfile->files, &sel, FILE_SEL_ADD, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
2015-01-04 02:36:42 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (idx = sel.last; idx >= 0; idx--) {
|
|
|
|
const FileDirEntry *file = filelist_file(sfile->files, idx);
|
2015-01-04 02:36:42 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* dont highlight readonly file (".." or ".") on box select */
|
|
|
|
if (FILENAME_IS_CURRPAR(file->relpath)) {
|
|
|
|
filelist_entry_select_set(
|
|
|
|
sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_HIGHLIGHTED, CHECK_ALL);
|
|
|
|
}
|
2015-01-04 02:36:42 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* make sure highlight_file is no readonly file */
|
|
|
|
if (sel.last == idx) {
|
|
|
|
params->highlight_file = idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
params->sel_first = sel.first;
|
|
|
|
params->sel_last = sel.last;
|
2020-03-06 16:56:42 +01:00
|
|
|
params->active_file = file_box_select_find_last_selected(sfile, region, &sel, event->mval);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
params->highlight_file = -1;
|
|
|
|
params->sel_first = params->sel_last = -1;
|
|
|
|
fileselect_file_set(sfile, params->active_file);
|
|
|
|
file_deselect_all(sfile, FILE_SEL_HIGHLIGHTED);
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
}
|
2011-03-20 00:34:08 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return result;
|
2011-03-20 00:34:08 +00:00
|
|
|
}
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
static int file_box_select_exec(bContext *C, wmOperator *op)
|
2009-01-21 19:28:28 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
rcti rect;
|
|
|
|
FileSelect ret;
|
2011-11-16 19:22:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_operator_properties_border_to_rcti(op, &rect);
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
|
|
|
|
const bool select = (sel_op != SEL_OP_SUB);
|
|
|
|
if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
|
|
|
|
file_deselect_all(sfile, FILE_SEL_SELECTED);
|
|
|
|
}
|
2011-11-16 19:22:14 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_fileselect_layout_isect_rect(sfile->layout, ®ion->v2d, &rect, &rect);
|
2011-03-14 19:56:13 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false);
|
2015-07-09 19:48:03 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* unselect '..' parent entry - it's not supposed to be selected if more than
|
|
|
|
* one file is selected */
|
2019-09-03 23:05:32 +02:00
|
|
|
filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
|
2015-07-09 19:48:03 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (FILE_SELECT_DIR == ret) {
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
}
|
|
|
|
else if (FILE_SELECT_FILE == ret) {
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 10:27:04 +10:00
|
|
|
void FILE_OT_select_box(wmOperatorType *ot)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Box Select";
|
|
|
|
ot->description = "Activate/select the file(s) contained in the border";
|
|
|
|
ot->idname = "FILE_OT_select_box";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = WM_gesture_box_invoke;
|
|
|
|
ot->exec = file_box_select_exec;
|
|
|
|
ot->modal = file_box_select_modal;
|
|
|
|
ot->poll = ED_operator_file_active;
|
|
|
|
ot->cancel = WM_gesture_box_cancel;
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
|
|
|
WM_operator_properties_gesture_box(ot);
|
|
|
|
WM_operator_properties_select_operation_simple(ot);
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Select Pick Operator
|
|
|
|
* \{ */
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
FileSelect ret;
|
|
|
|
rcti rect;
|
|
|
|
const bool extend = RNA_boolean_get(op->ptr, "extend");
|
|
|
|
const bool fill = RNA_boolean_get(op->ptr, "fill");
|
|
|
|
const bool do_diropen = RNA_boolean_get(op->ptr, "open");
|
2019-09-10 18:36:05 +02:00
|
|
|
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (region->regiontype != RGN_TYPE_WINDOW) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
rect.xmin = rect.xmax = event->mval[0];
|
|
|
|
rect.ymin = rect.ymax = event->mval[1];
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (!ED_fileselect_layout_is_inside_pt(sfile->layout, ®ion->v2d, rect.xmin, rect.ymin)) {
|
2020-08-07 11:34:59 +02:00
|
|
|
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile && sfile->params) {
|
|
|
|
int idx = sfile->params->highlight_file;
|
|
|
|
int numfiles = filelist_files_ensure(sfile->files);
|
2014-12-24 19:51:42 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if ((idx >= 0) && (idx < numfiles)) {
|
|
|
|
/* single select, deselect all selected first */
|
|
|
|
if (!extend) {
|
|
|
|
file_deselect_all(sfile, FILE_SEL_SELECTED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ret = file_select(C, &rect, extend ? FILE_SEL_TOGGLE : FILE_SEL_ADD, fill, do_diropen);
|
2015-07-09 19:48:03 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (extend) {
|
|
|
|
/* unselect '..' parent entry - it's not supposed to be selected if more
|
|
|
|
* than one file is selected */
|
2019-09-03 23:05:32 +02:00
|
|
|
filelist_entry_parent_select_set(sfile->files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-07-09 19:48:03 +02:00
|
|
|
|
2019-09-10 18:36:05 +02:00
|
|
|
if (ret == FILE_SELECT_NOTHING) {
|
|
|
|
if (deselect_all) {
|
|
|
|
file_deselect_all(sfile, FILE_SEL_SELECTED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (ret == FILE_SELECT_DIR) {
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-09-10 18:36:05 +02:00
|
|
|
else if (ret == FILE_SELECT_FILE) {
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_event_add_mousemove(CTX_wm_window(C)); /* for directory changes */
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
2009-03-10 23:14:41 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2009-02-14 14:25:48 +00:00
|
|
|
void FILE_OT_select(wmOperatorType *ot)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
2012-10-08 03:33:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Select";
|
|
|
|
ot->idname = "FILE_OT_select";
|
2019-09-10 18:36:05 +02:00
|
|
|
ot->description = "Handle mouse clicks to select and activate items";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = file_select_invoke;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
|
|
|
prop = RNA_def_boolean(ot->srna,
|
|
|
|
"extend",
|
|
|
|
false,
|
|
|
|
"Extend",
|
|
|
|
"Extend selection instead of deselecting everything first");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(
|
|
|
|
ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Open a directory when selecting it");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2019-09-10 18:36:05 +02:00
|
|
|
prop = RNA_def_boolean(ot->srna,
|
|
|
|
"deselect_all",
|
|
|
|
false,
|
|
|
|
"Deselect On Nothing",
|
|
|
|
"Deselect all when nothing under the cursor");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Select Walk Operator
|
|
|
|
* \{ */
|
|
|
|
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
/**
|
|
|
|
* \returns true if selection has changed
|
|
|
|
*/
|
2020-03-06 16:22:28 +01:00
|
|
|
static bool file_walk_select_selection_set(wmWindow *win,
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region,
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile,
|
|
|
|
const int direction,
|
|
|
|
const int numfiles,
|
|
|
|
const int active_old,
|
|
|
|
const int active_new,
|
|
|
|
const int other_site,
|
|
|
|
const bool has_selection,
|
|
|
|
const bool extend,
|
|
|
|
const bool fill)
|
|
|
|
{
|
|
|
|
FileSelectParams *params = sfile->params;
|
|
|
|
struct FileList *files = sfile->files;
|
|
|
|
const int last_sel = params->active_file; /* store old value */
|
|
|
|
int active = active_old; /* could use active_old instead, just for readability */
|
|
|
|
bool deselect = false;
|
|
|
|
|
|
|
|
BLI_assert(params);
|
|
|
|
|
2019-09-03 19:50:04 +02:00
|
|
|
if (numfiles == 0) {
|
|
|
|
/* No files visible, nothing to do. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (has_selection) {
|
|
|
|
if (extend && filelist_entry_select_index_get(files, active_old, CHECK_ALL) &&
|
|
|
|
filelist_entry_select_index_get(files, active_new, CHECK_ALL)) {
|
|
|
|
/* conditions for deselecting: initial file is selected, new file is
|
|
|
|
* selected and either other_side isn't selected/found or we use fill */
|
|
|
|
deselect = (fill || other_site == -1 ||
|
|
|
|
!filelist_entry_select_index_get(files, other_site, CHECK_ALL));
|
|
|
|
|
|
|
|
/* don't change highlight_file here since we either want to deselect active or we want
|
|
|
|
* to walk through a block of selected files without selecting/deselecting anything */
|
|
|
|
params->active_file = active_new;
|
|
|
|
/* but we want to change active if we use fill
|
|
|
|
* (needed to get correct selection bounds) */
|
|
|
|
if (deselect && fill) {
|
|
|
|
active = active_new;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* regular selection change */
|
|
|
|
params->active_file = active = active_new;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* select last file */
|
2020-03-02 16:05:59 +01:00
|
|
|
if (ELEM(direction, UI_SELECT_WALK_UP, UI_SELECT_WALK_LEFT)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
params->active_file = active = numfiles - 1;
|
|
|
|
}
|
|
|
|
/* select first file */
|
2020-03-02 16:05:59 +01:00
|
|
|
else if (ELEM(direction, UI_SELECT_WALK_DOWN, UI_SELECT_WALK_RIGHT)) {
|
2019-09-03 23:05:32 +02:00
|
|
|
params->active_file = active = 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (active < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (extend) {
|
|
|
|
/* highlight the active walker file for extended selection for better visual feedback */
|
|
|
|
params->highlight_file = params->active_file;
|
|
|
|
|
|
|
|
/* unselect '..' parent entry - it's not supposed to be selected if more
|
|
|
|
* than one file is selected */
|
2019-09-03 23:05:32 +02:00
|
|
|
filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* deselect all first */
|
|
|
|
file_deselect_all(sfile, FILE_SEL_SELECTED);
|
|
|
|
|
|
|
|
/* highlight file under mouse pos */
|
|
|
|
params->highlight_file = -1;
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_event_add_mousemove(win);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* do the actual selection */
|
|
|
|
if (fill) {
|
|
|
|
FileSelection sel = {MIN2(active, last_sel), MAX2(active, last_sel)};
|
|
|
|
|
|
|
|
/* fill selection between last and first selected file */
|
|
|
|
filelist_entries_select_index_range_set(
|
|
|
|
files, &sel, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
|
|
|
|
/* entire sel is cleared here, so select active again */
|
|
|
|
if (deselect) {
|
|
|
|
filelist_entry_select_index_set(files, active, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
|
|
|
|
}
|
2019-09-03 23:05:32 +02:00
|
|
|
|
|
|
|
/* unselect '..' parent entry - it's not supposed to be selected if more
|
|
|
|
* than one file is selected */
|
|
|
|
if ((sel.last - sel.first) > 1) {
|
|
|
|
filelist_entry_parent_select_set(files, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
filelist_entry_select_index_set(
|
|
|
|
files, active, deselect ? FILE_SEL_REMOVE : FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL);
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_assert(IN_RANGE(active, -1, numfiles));
|
|
|
|
fileselect_file_set(sfile, params->active_file);
|
|
|
|
|
|
|
|
/* ensure newly selected file is inside viewbounds */
|
2020-03-06 16:56:42 +01:00
|
|
|
file_ensure_inside_viewbounds(region, sfile, params->active_file);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* selection changed */
|
|
|
|
return true;
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* \returns true if selection has changed
|
|
|
|
*/
|
2019-04-17 06:17:24 +02:00
|
|
|
static bool file_walk_select_do(bContext *C,
|
|
|
|
SpaceFile *sfile,
|
|
|
|
FileSelectParams *params,
|
|
|
|
const int direction,
|
|
|
|
const bool extend,
|
|
|
|
const bool fill)
|
|
|
|
{
|
2020-03-06 16:22:28 +01:00
|
|
|
wmWindow *win = CTX_wm_window(C);
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
struct FileList *files = sfile->files;
|
|
|
|
const int numfiles = filelist_files_ensure(files);
|
|
|
|
const bool has_selection = file_is_any_selected(files);
|
|
|
|
const int active_old = params->active_file;
|
|
|
|
int active_new = -1;
|
|
|
|
int other_site = -1; /* file on the other site of active_old */
|
|
|
|
|
|
|
|
/* *** get all needed files for handling selection *** */
|
|
|
|
|
2019-09-03 19:50:04 +02:00
|
|
|
if (numfiles == 0) {
|
|
|
|
/* No files visible, nothing to do. */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (has_selection) {
|
2020-03-06 16:56:42 +01:00
|
|
|
FileLayout *layout = ED_fileselect_get_layout(sfile, region);
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-02 16:05:59 +01:00
|
|
|
if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_UP) ||
|
|
|
|
(layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_LEFT)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
active_new = active_old - 1;
|
|
|
|
other_site = active_old + 1;
|
|
|
|
}
|
2020-03-02 16:05:59 +01:00
|
|
|
else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_DOWN) ||
|
|
|
|
(layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_RIGHT)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
active_new = active_old + 1;
|
|
|
|
other_site = active_old - 1;
|
|
|
|
}
|
2020-03-02 16:05:59 +01:00
|
|
|
else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_LEFT) ||
|
|
|
|
(layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_UP)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
active_new = active_old - idx_shift;
|
|
|
|
other_site = active_old + idx_shift;
|
|
|
|
}
|
2020-03-02 16:05:59 +01:00
|
|
|
else if ((layout->flag & FILE_LAYOUT_HOR && direction == UI_SELECT_WALK_RIGHT) ||
|
|
|
|
(layout->flag & FILE_LAYOUT_VER && direction == UI_SELECT_WALK_DOWN)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
active_new = active_old + idx_shift;
|
|
|
|
other_site = active_old - idx_shift;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_assert(0);
|
|
|
|
}
|
|
|
|
|
2019-09-03 23:05:32 +02:00
|
|
|
if (!IN_RANGE(active_new, -1, numfiles)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
if (extend) {
|
|
|
|
/* extend to invalid file -> abort */
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
/* if we don't extend, selecting '..' (index == 0) is allowed so
|
|
|
|
* using key selection to go to parent directory is possible */
|
2020-07-03 17:30:31 +02:00
|
|
|
if (active_new != 0) {
|
2019-04-17 06:17:24 +02:00
|
|
|
/* select initial file */
|
|
|
|
active_new = active_old;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!IN_RANGE(other_site, 0, numfiles)) {
|
|
|
|
other_site = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-06 16:22:28 +01:00
|
|
|
return file_walk_select_selection_set(win,
|
2020-03-06 16:56:42 +01:00
|
|
|
region,
|
2019-04-17 06:17:24 +02:00
|
|
|
sfile,
|
|
|
|
direction,
|
|
|
|
numfiles,
|
|
|
|
active_old,
|
|
|
|
active_new,
|
|
|
|
other_site,
|
|
|
|
has_selection,
|
|
|
|
extend,
|
|
|
|
fill);
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static int file_walk_select_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
|
|
|
|
FileSelectParams *params = sfile->params;
|
|
|
|
const int direction = RNA_enum_get(op->ptr, "direction");
|
|
|
|
const bool extend = RNA_boolean_get(op->ptr, "extend");
|
|
|
|
const bool fill = RNA_boolean_get(op->ptr, "fill");
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (file_walk_select_do(C, sfile, params, direction, extend, fill)) {
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_select_walk(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Walk Select/Deselect File";
|
|
|
|
ot->description = "Select/Deselect files by walking through them";
|
|
|
|
ot->idname = "FILE_OT_select_walk";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = file_walk_select_invoke;
|
|
|
|
ot->poll = ED_operator_file_active;
|
|
|
|
|
|
|
|
/* properties */
|
2020-03-02 16:05:59 +01:00
|
|
|
WM_operator_properties_select_walk_direction(ot);
|
2019-04-17 06:17:24 +02:00
|
|
|
prop = RNA_def_boolean(ot->srna,
|
|
|
|
"extend",
|
|
|
|
false,
|
|
|
|
"Extend",
|
|
|
|
"Extend selection instead of deselecting everything first");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(
|
|
|
|
ot->srna, "fill", false, "Fill", "Select everything beginning with the last selection");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
File Browser Arrow Keys Navigation
Adds support for selecting/deselecting files in File Browser using the
arrow keys. All directions (up, down, left, right) are possible.
When to Select, When to Deselect?
Standard behaviour is selecting, however if we move into a block of
already selected files (meaning 2+ files are selected) we start
deselecting
Possible Selection Methods
Simple selection (arrow-key): All other files are deselected
Expand selection (Shift+arrow key): Add to/remove from existing
selection
ill-Expand selection (Ctrl+Shift+arrow key): Add to/remove from existing
selection and fill everything in-between
From which file do we start navigating?
From each available selection method (Mouse-, Walk-, All-, Border
Select), we use the last selected file. If there's no selection at all
we use the first (down/right arrow) or last (up/left arrow) file.
(Ideally, the view would automatically be set to the new selection, but
this behaviour overlaps with an other patch I've been working on, so
prefer to do that separately)
(Also tweaks color for highlighted file for better feedback)
D1297, Review done by @campbellbarton, thx a lot :)
2015-06-11 17:20:29 +02:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Select All Operator
|
|
|
|
* \{ */
|
|
|
|
|
2019-06-22 20:10:53 +10:00
|
|
|
static int file_select_all_exec(bContext *C, wmOperator *op)
|
2009-01-21 19:28:28 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
FileSelection sel;
|
|
|
|
const int numfiles = filelist_files_ensure(sfile->files);
|
2019-06-22 20:10:53 +10:00
|
|
|
int action = RNA_enum_get(op->ptr, "action");
|
|
|
|
|
|
|
|
if (action == SEL_TOGGLE) {
|
|
|
|
action = file_is_any_selected(sfile->files) ? SEL_DESELECT : SEL_SELECT;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
sel.first = 0;
|
|
|
|
sel.last = numfiles - 1;
|
|
|
|
|
2019-06-22 20:10:53 +10:00
|
|
|
FileCheckType check_type;
|
|
|
|
FileSelType filesel_type;
|
|
|
|
|
|
|
|
switch (action) {
|
|
|
|
case SEL_SELECT:
|
|
|
|
case SEL_INVERT: {
|
|
|
|
check_type = (sfile->params->flag & FILE_DIRSEL_ONLY) ? CHECK_DIRS : CHECK_FILES;
|
|
|
|
filesel_type = (action == SEL_INVERT) ? FILE_SEL_TOGGLE : FILE_SEL_ADD;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case SEL_DESELECT: {
|
|
|
|
check_type = CHECK_ALL;
|
|
|
|
filesel_type = FILE_SEL_REMOVE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
BLI_assert(0);
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2019-06-22 20:10:53 +10:00
|
|
|
filelist_entries_select_index_range_set(
|
|
|
|
sfile->files, &sel, filesel_type, FILE_SEL_SELECTED, check_type);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-06-22 20:10:53 +10:00
|
|
|
sfile->params->active_file = -1;
|
|
|
|
if (action != SEL_DESELECT) {
|
|
|
|
for (int i = 0; i < numfiles; i++) {
|
2019-04-17 06:17:24 +02:00
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, check_type)) {
|
|
|
|
sfile->params->active_file = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file_draw_check(C);
|
2020-03-06 16:22:28 +01:00
|
|
|
WM_event_add_mousemove(CTX_wm_window(C));
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-01-21 19:28:28 +00:00
|
|
|
}
|
|
|
|
|
2018-07-03 15:44:56 +02:00
|
|
|
void FILE_OT_select_all(wmOperatorType *ot)
|
2009-01-21 19:28:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "(De)select All Files";
|
|
|
|
ot->description = "Select or deselect all files";
|
|
|
|
ot->idname = "FILE_OT_select_all";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_select_all_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
2019-06-22 20:10:53 +10:00
|
|
|
WM_operator_properties_select_all(ot);
|
2009-01-21 19:28:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Select Bookmark Operator
|
|
|
|
* \{ */
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-01-15 23:24:20 +11:00
|
|
|
/* Note we could get rid of this one, but it's used by some addon so...
|
|
|
|
* Does not hurt keeping it around for now. */
|
2009-11-22 22:23:58 +00:00
|
|
|
static int bookmark_select_exec(bContext *C, wmOperator *op)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
PropertyRNA *prop;
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "dir"))) {
|
|
|
|
char entry[256];
|
|
|
|
FileSelectParams *params = sfile->params;
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_property_string_get(op->ptr, prop, entry);
|
|
|
|
BLI_strncpy(params->dir, entry, sizeof(params->dir));
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_file_change_dir(C);
|
2009-01-21 19:28:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-01-06 14:42:54 +00:00
|
|
|
}
|
|
|
|
|
2009-02-14 14:25:48 +00:00
|
|
|
void FILE_OT_select_bookmark(wmOperatorType *ot)
|
2009-01-06 14:42:54 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
2012-10-08 03:33:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Select Directory";
|
|
|
|
ot->description = "Select a bookmarked directory";
|
|
|
|
ot->idname = "FILE_OT_select_bookmark";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = bookmark_select_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2009-06-29 20:23:40 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
|
|
|
prop = RNA_def_string(ot->srna, "dir", NULL, FILE_MAXDIR, "Dir", "");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2009-01-18 18:24:11 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Add Bookmark Operator
|
|
|
|
* \{ */
|
|
|
|
|
2010-10-15 01:36:14 +00:00
|
|
|
static int bookmark_add_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-06-29 22:16:48 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
|
|
|
struct FileSelectParams *params = ED_fileselect_get_params(sfile);
|
2009-06-29 22:16:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (params->dir[0] != '\0') {
|
|
|
|
char name[FILE_MAX];
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-12-06 13:10:30 -08:00
|
|
|
fsmenu_insert_entry(
|
|
|
|
fsmenu, FS_CATEGORY_BOOKMARKS, params->dir, NULL, ICON_FILE_FOLDER, FS_INSERT_SAVE);
|
2020-03-07 13:23:26 +11:00
|
|
|
BLI_join_dirfile(name,
|
|
|
|
sizeof(name),
|
|
|
|
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
|
|
|
|
BLENDER_BOOKMARK_FILE);
|
2019-04-17 06:17:24 +02:00
|
|
|
fsmenu_write_file(fsmenu, name);
|
|
|
|
}
|
2009-06-29 22:16:48 +00:00
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_refresh(area);
|
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-06-29 22:16:48 +00:00
|
|
|
}
|
|
|
|
|
2009-11-28 14:37:21 +00:00
|
|
|
void FILE_OT_bookmark_add(wmOperatorType *ot)
|
2009-06-29 22:16:48 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Add Bookmark";
|
|
|
|
ot->description = "Add a bookmark for the selected/active directory";
|
|
|
|
ot->idname = "FILE_OT_bookmark_add";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = bookmark_add_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2009-06-29 22:16:48 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Delete Bookmark Operator
|
|
|
|
* \{ */
|
|
|
|
|
2009-11-22 22:23:58 +00:00
|
|
|
static int bookmark_delete_exec(bContext *C, wmOperator *op)
|
2009-06-29 22:16:48 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
|
|
|
int nentries = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
|
|
|
|
|
|
|
|
PropertyRNA *prop = RNA_struct_find_property(op->ptr, "index");
|
|
|
|
|
|
|
|
if (prop) {
|
|
|
|
int index;
|
|
|
|
if (RNA_property_is_set(op->ptr, prop)) {
|
|
|
|
index = RNA_property_int_get(op->ptr, prop);
|
|
|
|
}
|
|
|
|
else { /* if index unset, use active bookmark... */
|
|
|
|
index = sfile->bookmarknr;
|
|
|
|
}
|
|
|
|
if ((index > -1) && (index < nentries)) {
|
|
|
|
char name[FILE_MAX];
|
|
|
|
|
|
|
|
fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
|
2020-03-07 13:23:26 +11:00
|
|
|
BLI_join_dirfile(name,
|
|
|
|
sizeof(name),
|
|
|
|
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
|
|
|
|
BLENDER_BOOKMARK_FILE);
|
2019-04-17 06:17:24 +02:00
|
|
|
fsmenu_write_file(fsmenu, name);
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_refresh(area);
|
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-06-29 22:16:48 +00:00
|
|
|
}
|
|
|
|
|
2013-10-08 13:16:14 +00:00
|
|
|
void FILE_OT_bookmark_delete(wmOperatorType *ot)
|
2009-06-29 22:16:48 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
2012-10-08 03:33:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Delete Bookmark";
|
|
|
|
ot->description = "Delete selected bookmark";
|
|
|
|
ot->idname = "FILE_OT_bookmark_delete";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = bookmark_delete_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2009-06-29 22:16:48 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
|
|
|
prop = RNA_def_int(ot->srna, "index", -1, -1, 20000, "Index", "", -1, 20000);
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2009-06-29 22:16:48 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Cleanup Bookmark Operator
|
|
|
|
* \{ */
|
|
|
|
|
2015-02-11 17:07:52 +01:00
|
|
|
static int bookmark_cleanup_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
|
|
|
struct FSMenuEntry *fsme_next, *fsme = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
|
|
|
|
int index;
|
|
|
|
bool changed = false;
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
for (index = 0; fsme; fsme = fsme_next) {
|
|
|
|
fsme_next = fsme->next;
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (!BLI_is_dir(fsme->path)) {
|
|
|
|
fsmenu_remove_entry(fsmenu, FS_CATEGORY_BOOKMARKS, index);
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (changed) {
|
|
|
|
char name[FILE_MAX];
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2020-03-07 13:23:26 +11:00
|
|
|
BLI_join_dirfile(name,
|
|
|
|
sizeof(name),
|
|
|
|
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
|
|
|
|
BLENDER_BOOKMARK_FILE);
|
2019-04-17 06:17:24 +02:00
|
|
|
fsmenu_write_file(fsmenu, name);
|
2019-05-15 16:20:14 +02:00
|
|
|
fsmenu_refresh_bookmarks_status(CTX_wm_manager(C), fsmenu);
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_refresh(area);
|
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2015-02-11 17:07:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_bookmark_cleanup(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Cleanup Bookmarks";
|
|
|
|
ot->description = "Delete all invalid bookmarks";
|
|
|
|
ot->idname = "FILE_OT_bookmark_cleanup";
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = bookmark_cleanup_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2015-02-11 17:07:52 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
2015-02-11 17:07:52 +01:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Reorder Bookmark Operator
|
|
|
|
* \{ */
|
|
|
|
|
2015-02-11 00:09:45 +01:00
|
|
|
enum {
|
2019-04-17 06:17:24 +02:00
|
|
|
FILE_BOOKMARK_MOVE_TOP = -2,
|
|
|
|
FILE_BOOKMARK_MOVE_UP = -1,
|
|
|
|
FILE_BOOKMARK_MOVE_DOWN = 1,
|
|
|
|
FILE_BOOKMARK_MOVE_BOTTOM = 2,
|
2015-02-11 00:09:45 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
static int bookmark_move_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
|
|
|
struct FSMenuEntry *fsmentry = ED_fsmenu_get_category(fsmenu, FS_CATEGORY_BOOKMARKS);
|
|
|
|
const struct FSMenuEntry *fsmentry_org = fsmentry;
|
|
|
|
|
|
|
|
char fname[FILE_MAX];
|
|
|
|
|
|
|
|
const int direction = RNA_enum_get(op->ptr, "direction");
|
|
|
|
const int totitems = ED_fsmenu_get_nentries(fsmenu, FS_CATEGORY_BOOKMARKS);
|
|
|
|
const int act_index = sfile->bookmarknr;
|
|
|
|
int new_index;
|
|
|
|
|
|
|
|
if (totitems < 2) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (direction) {
|
|
|
|
case FILE_BOOKMARK_MOVE_TOP:
|
|
|
|
new_index = 0;
|
|
|
|
break;
|
|
|
|
case FILE_BOOKMARK_MOVE_BOTTOM:
|
|
|
|
new_index = totitems - 1;
|
|
|
|
break;
|
|
|
|
case FILE_BOOKMARK_MOVE_UP:
|
|
|
|
case FILE_BOOKMARK_MOVE_DOWN:
|
|
|
|
default:
|
|
|
|
new_index = (totitems + act_index + direction) % totitems;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_index == act_index) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_linklist_move_item((LinkNode **)&fsmentry, act_index, new_index);
|
|
|
|
if (fsmentry != fsmentry_org) {
|
|
|
|
ED_fsmenu_set_category(fsmenu, FS_CATEGORY_BOOKMARKS, fsmentry);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Need to update active bookmark number. */
|
|
|
|
sfile->bookmarknr = new_index;
|
|
|
|
|
2020-03-07 13:23:26 +11:00
|
|
|
BLI_join_dirfile(fname,
|
|
|
|
sizeof(fname),
|
|
|
|
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
|
|
|
|
BLENDER_BOOKMARK_FILE);
|
2019-04-17 06:17:24 +02:00
|
|
|
fsmenu_write_file(fsmenu, fname);
|
|
|
|
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2015-02-11 00:09:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_bookmark_move(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
static const EnumPropertyItem slot_move[] = {
|
|
|
|
{FILE_BOOKMARK_MOVE_TOP, "TOP", 0, "Top", "Top of the list"},
|
|
|
|
{FILE_BOOKMARK_MOVE_UP, "UP", 0, "Up", ""},
|
|
|
|
{FILE_BOOKMARK_MOVE_DOWN, "DOWN", 0, "Down", ""},
|
|
|
|
{FILE_BOOKMARK_MOVE_BOTTOM, "BOTTOM", 0, "Bottom", "Bottom of the list"},
|
|
|
|
{0, NULL, 0, NULL, NULL}};
|
2015-02-11 00:09:45 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Move Bookmark";
|
|
|
|
ot->idname = "FILE_OT_bookmark_move";
|
|
|
|
ot->description = "Move the active bookmark up/down in the list";
|
2015-02-11 00:09:45 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->poll = ED_operator_file_active;
|
|
|
|
ot->exec = bookmark_move_exec;
|
2015-02-11 00:09:45 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* flags */
|
|
|
|
ot->flag = OPTYPE_REGISTER; /* No undo! */
|
2015-02-11 00:09:45 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_def_enum(ot->srna,
|
|
|
|
"direction",
|
|
|
|
slot_move,
|
|
|
|
0,
|
|
|
|
"Direction",
|
|
|
|
"Direction to move the active bookmark towards");
|
2015-02-11 00:09:45 +01:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Reset Recent Blend Files Operator
|
|
|
|
* \{ */
|
|
|
|
|
2012-09-17 22:34:42 +00:00
|
|
|
static int reset_recent_exec(bContext *C, wmOperator *UNUSED(op))
|
2012-09-17 21:38:04 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
char name[FILE_MAX];
|
|
|
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
while (ED_fsmenu_get_entry(fsmenu, FS_CATEGORY_RECENT, 0) != NULL) {
|
|
|
|
fsmenu_remove_entry(fsmenu, FS_CATEGORY_RECENT, 0);
|
|
|
|
}
|
2020-03-07 13:23:26 +11:00
|
|
|
BLI_join_dirfile(name,
|
|
|
|
sizeof(name),
|
|
|
|
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
|
|
|
|
BLENDER_BOOKMARK_FILE);
|
2019-04-17 06:17:24 +02:00
|
|
|
fsmenu_write_file(fsmenu, name);
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2015-02-11 00:09:45 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2012-09-17 21:38:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_reset_recent(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Reset Recent";
|
|
|
|
ot->description = "Reset Recent files";
|
|
|
|
ot->idname = "FILE_OT_reset_recent";
|
2012-09-17 21:38:04 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = reset_recent_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2012-09-17 21:38:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Highlight File Operator
|
|
|
|
* \{ */
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
int file_highlight_set(SpaceFile *sfile, ARegion *region, int mx, int my)
|
2009-01-21 19:28:28 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
View2D *v2d = ®ion->v2d;
|
2019-04-17 06:17:24 +02:00
|
|
|
FileSelectParams *params;
|
|
|
|
int numfiles, origfile;
|
2011-03-14 19:56:13 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (sfile == NULL || sfile->files == NULL) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
params = ED_fileselect_get_params(sfile);
|
2009-03-14 18:15:28 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
origfile = params->highlight_file;
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
mx -= region->winrct.xmin;
|
|
|
|
my -= region->winrct.ymin;
|
2009-07-28 16:46:14 +00:00
|
|
|
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
float fx, fy;
|
|
|
|
int highlight_file;
|
2011-03-14 19:56:13 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
UI_view2d_region_to_view(v2d, mx, my, &fx, &fy);
|
2011-03-14 19:56:13 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
highlight_file = ED_fileselect_layout_offset(
|
|
|
|
sfile->layout, (int)(v2d->tot.xmin + fx), (int)(v2d->tot.ymax - fy));
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if ((highlight_file >= 0) && (highlight_file < numfiles)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
params->highlight_file = highlight_file;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
params->highlight_file = -1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
params->highlight_file = -1;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return (params->highlight_file != origfile);
|
2009-01-28 11:27:25 +00:00
|
|
|
}
|
|
|
|
|
2013-03-13 09:03:46 +00:00
|
|
|
static int file_highlight_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
2009-01-28 11:27:25 +00:00
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
ARegion *region = CTX_wm_region(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
if (!file_highlight_set(sfile, region, event->x, event->y)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-28 16:46:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2009-01-21 19:28:28 +00:00
|
|
|
}
|
|
|
|
|
2009-02-14 14:25:48 +00:00
|
|
|
void FILE_OT_highlight(struct wmOperatorType *ot)
|
2009-01-21 19:28:28 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Highlight File";
|
|
|
|
ot->description = "Highlight selected file(s)";
|
|
|
|
ot->idname = "FILE_OT_highlight";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = file_highlight_invoke;
|
|
|
|
ot->poll = ED_operator_file_active;
|
2009-01-21 19:28:28 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Sort from Column Operator
|
|
|
|
* \{ */
|
|
|
|
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
static int file_column_sort_ui_context_invoke(bContext *C,
|
|
|
|
wmOperator *UNUSED(op),
|
|
|
|
const wmEvent *event)
|
|
|
|
{
|
2020-03-06 16:56:42 +01:00
|
|
|
const ARegion *region = CTX_wm_region(C);
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
|
|
|
|
if (file_attribute_column_header_is_inside(
|
2020-03-06 16:56:42 +01:00
|
|
|
®ion->v2d, sfile->layout, event->mval[0], event->mval[1])) {
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
const FileAttributeColumnType column_type = file_attribute_column_type_find_isect(
|
2020-03-06 16:56:42 +01:00
|
|
|
®ion->v2d, sfile->params, sfile->layout, event->mval[0]);
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
|
|
|
|
if (column_type != COLUMN_NONE) {
|
|
|
|
const FileAttributeColumn *column = &sfile->layout->attribute_columns[column_type];
|
|
|
|
|
|
|
|
if (column->sort_type != FILE_SORT_NONE) {
|
|
|
|
if (sfile->params->sort == column->sort_type) {
|
|
|
|
/* Already sorting by selected column -> toggle sort invert (three state logic). */
|
|
|
|
sfile->params->flag ^= FILE_SORT_INVERT;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sfile->params->sort = column->sort_type;
|
|
|
|
sfile->params->flag &= ~FILE_SORT_INVERT;
|
|
|
|
}
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_sort_column_ui_context(wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Sort from Column";
|
|
|
|
ot->description = "Change sorting to use column under cursor";
|
|
|
|
ot->idname = "FILE_OT_sort_column_ui_context";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = file_column_sort_ui_context_invoke;
|
|
|
|
ot->poll = ED_operator_file_active;
|
|
|
|
|
|
|
|
ot->flag = OPTYPE_INTERNAL;
|
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Cancel File Selector Operator
|
|
|
|
* \{ */
|
2009-01-28 11:27:25 +00:00
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool file_operator_poll(bContext *C)
|
2009-09-20 17:23:57 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
bool poll = ED_operator_file_active(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2009-09-20 17:23:57 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!sfile || !sfile->op) {
|
2019-04-17 06:17:24 +02:00
|
|
|
poll = 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-09-20 17:23:57 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return poll;
|
2009-09-20 17:23:57 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
static int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused))
|
|
|
|
{
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
wmOperator *op = sfile->op;
|
|
|
|
|
|
|
|
sfile->op = NULL;
|
|
|
|
|
|
|
|
WM_event_fileselect_event(wm, op, EVT_FILESELECT_CANCEL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
2009-02-14 14:25:48 +00:00
|
|
|
void FILE_OT_cancel(struct wmOperatorType *ot)
|
2009-01-28 11:27:25 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Cancel File Load";
|
|
|
|
ot->description = "Cancel loading of selected file";
|
|
|
|
ot->idname = "FILE_OT_cancel";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_cancel_exec;
|
|
|
|
ot->poll = file_operator_poll;
|
2009-01-28 11:27:25 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Operator Utilities
|
|
|
|
* \{ */
|
|
|
|
|
2018-06-05 15:10:33 +02:00
|
|
|
void file_sfile_to_operator_ex(bContext *C, wmOperator *op, SpaceFile *sfile, char *filepath)
|
2010-09-17 09:27:31 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
/* XXX, not real length */
|
|
|
|
BLI_join_dirfile(filepath, FILE_MAX, sfile->params->dir, sfile->params->file);
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "relative_path"))) {
|
|
|
|
if (RNA_property_boolean_get(op->ptr, prop)) {
|
|
|
|
BLI_path_rel(filepath, BKE_main_blendfile_path(bmain));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
|
|
|
|
RNA_property_string_set(op->ptr, prop, sfile->params->file);
|
|
|
|
}
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
|
|
|
|
RNA_property_string_set(op->ptr, prop, sfile->params->dir);
|
|
|
|
}
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
|
|
|
|
RNA_property_string_set(op->ptr, prop, filepath);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* some ops have multiple files to select */
|
|
|
|
/* this is called on operators check() so clear collections first since
|
|
|
|
* they may be already set. */
|
|
|
|
{
|
|
|
|
int i, numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "files"))) {
|
|
|
|
PointerRNA itemptr;
|
|
|
|
int num_files = 0;
|
|
|
|
RNA_property_collection_clear(op->ptr, prop);
|
|
|
|
for (i = 0; i < numfiles; i++) {
|
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, CHECK_FILES)) {
|
|
|
|
FileDirEntry *file = filelist_file(sfile->files, i);
|
2020-05-26 08:14:41 -07:00
|
|
|
/* Cannot (currently) mix regular items and alias/shortcuts in multiple selection. */
|
|
|
|
if (!file->redirection_path) {
|
|
|
|
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
|
|
|
RNA_string_set(&itemptr, "name", file->relpath);
|
|
|
|
num_files++;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
/* make sure the file specified in the filename button is added even if no
|
|
|
|
* files selected */
|
|
|
|
if (0 == num_files) {
|
|
|
|
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
|
|
|
RNA_string_set(&itemptr, "name", sfile->params->file);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "dirs"))) {
|
|
|
|
PointerRNA itemptr;
|
|
|
|
int num_dirs = 0;
|
|
|
|
RNA_property_collection_clear(op->ptr, prop);
|
|
|
|
for (i = 0; i < numfiles; i++) {
|
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, CHECK_DIRS)) {
|
|
|
|
FileDirEntry *file = filelist_file(sfile->files, i);
|
|
|
|
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
|
|
|
RNA_string_set(&itemptr, "name", file->relpath);
|
|
|
|
num_dirs++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* make sure the directory specified in the button is added even if no
|
|
|
|
* directory selected */
|
|
|
|
if (0 == num_dirs) {
|
|
|
|
RNA_property_collection_add(op->ptr, prop, &itemptr);
|
|
|
|
RNA_string_set(&itemptr, "name", sfile->params->dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-17 09:27:31 +00:00
|
|
|
}
|
2018-06-05 15:10:33 +02:00
|
|
|
void file_sfile_to_operator(bContext *C, wmOperator *op, SpaceFile *sfile)
|
2015-11-04 14:24:46 +01:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char filepath[FILE_MAX];
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
file_sfile_to_operator_ex(C, op, sfile, filepath);
|
2015-11-04 14:24:46 +01:00
|
|
|
}
|
2010-09-17 09:27:31 +00:00
|
|
|
|
2018-06-05 15:10:33 +02:00
|
|
|
void file_operator_to_sfile(bContext *C, SpaceFile *sfile, wmOperator *op)
|
2010-09-17 09:27:31 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
/* If neither of the above are set, split the filepath back */
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) {
|
|
|
|
char filepath[FILE_MAX];
|
|
|
|
RNA_property_string_get(op->ptr, prop, filepath);
|
|
|
|
BLI_split_dirfile(filepath,
|
|
|
|
sfile->params->dir,
|
|
|
|
sfile->params->file,
|
|
|
|
sizeof(sfile->params->dir),
|
|
|
|
sizeof(sfile->params->file));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "filename"))) {
|
|
|
|
RNA_property_string_get(op->ptr, prop, sfile->params->file);
|
|
|
|
}
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
|
|
|
|
RNA_property_string_get(op->ptr, prop, sfile->params->dir);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we could check for relative_path property which is used when converting
|
|
|
|
* in the other direction but doesn't hurt to do this every time */
|
|
|
|
BLI_path_abs(sfile->params->dir, BKE_main_blendfile_path(bmain));
|
|
|
|
|
|
|
|
/* XXX, files and dirs updates missing, not really so important though */
|
2010-09-17 09:27:31 +00:00
|
|
|
}
|
|
|
|
|
2015-11-04 14:24:46 +01:00
|
|
|
/**
|
|
|
|
* Use to set the file selector path from some arbitrary source.
|
|
|
|
*/
|
|
|
|
void file_sfile_filepath_set(SpaceFile *sfile, const char *filepath)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_assert(BLI_exists(filepath));
|
|
|
|
|
|
|
|
if (BLI_is_dir(filepath)) {
|
|
|
|
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if ((sfile->params->flag & FILE_DIRSEL_ONLY) == 0) {
|
|
|
|
BLI_split_dirfile(filepath,
|
|
|
|
sfile->params->dir,
|
|
|
|
sfile->params->file,
|
|
|
|
sizeof(sfile->params->dir),
|
|
|
|
sizeof(sfile->params->file));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BLI_split_dir_part(filepath, sfile->params->dir, sizeof(sfile->params->dir));
|
|
|
|
}
|
|
|
|
}
|
2015-11-04 14:24:46 +01:00
|
|
|
}
|
|
|
|
|
2015-02-17 08:52:19 +11:00
|
|
|
void file_draw_check(bContext *C)
|
2010-09-17 09:27:31 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
wmOperator *op = sfile->op;
|
|
|
|
if (op) { /* fail on reload */
|
|
|
|
if (op->type->check) {
|
|
|
|
file_sfile_to_operator(C, op, sfile);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* redraw */
|
|
|
|
if (op->type->check(C, op)) {
|
|
|
|
file_operator_to_sfile(C, sfile, op);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* redraw, else the changed settings wont get updated */
|
|
|
|
ED_area_tag_redraw(CTX_wm_area(C));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-17 09:27:31 +00:00
|
|
|
}
|
|
|
|
|
2015-02-17 08:52:19 +11:00
|
|
|
/* for use with; UI_block_func_set */
|
|
|
|
void file_draw_check_cb(bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
file_draw_check(C);
|
2015-02-17 08:52:19 +11:00
|
|
|
}
|
|
|
|
|
2014-02-03 18:55:59 +11:00
|
|
|
bool file_draw_check_exists(SpaceFile *sfile)
|
2010-09-17 09:27:31 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile->op) { /* fails on reload */
|
2019-09-16 18:14:23 +02:00
|
|
|
if (sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING)) {
|
|
|
|
char filepath[FILE_MAX];
|
|
|
|
BLI_join_dirfile(filepath, sizeof(filepath), sfile->params->dir, sfile->params->file);
|
|
|
|
if (BLI_is_file(filepath)) {
|
|
|
|
return true;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-09-17 09:27:31 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return false;
|
2010-09-17 09:27:31 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Execute File Window Operator
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static int file_exec(bContext *C, wmOperator *exec_op)
|
2009-01-28 11:27:25 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2020-05-26 08:14:41 -07:00
|
|
|
struct FileDirEntry *file = filelist_file(sfile->files, sfile->params->active_file);
|
2019-04-17 06:17:24 +02:00
|
|
|
char filepath[FILE_MAX];
|
|
|
|
|
2020-05-26 08:14:41 -07:00
|
|
|
if (file && file->redirection_path) {
|
|
|
|
/* redirection_path is an absolute path that takes precedence
|
|
|
|
* over using sfile->params->dir + sfile->params->file. */
|
|
|
|
BLI_split_dirfile(file->redirection_path,
|
|
|
|
sfile->params->dir,
|
|
|
|
sfile->params->file,
|
|
|
|
sizeof(sfile->params->dir),
|
|
|
|
sizeof(sfile->params->file));
|
|
|
|
/* Update relpath with redirected filename as well so that the alternative
|
|
|
|
* combination of sfile->params->dir + relpath remains valid as well. */
|
|
|
|
MEM_freeN(file->relpath);
|
|
|
|
file->relpath = BLI_strdup(sfile->params->file);
|
|
|
|
}
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* directory change */
|
|
|
|
if (file && (file->typeflag & FILE_TYPE_DIR)) {
|
|
|
|
if (!file->relpath) {
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (FILENAME_IS_PARENT(file->relpath)) {
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_parent_dir(sfile->params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_normalize(BKE_main_blendfile_path(bmain), sfile->params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_path_append(sfile->params->dir, sizeof(sfile->params->dir) - 1, file->relpath);
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_slash_ensure(sfile->params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
ED_file_change_dir(C);
|
|
|
|
}
|
|
|
|
/* opening file - sends events now, so things get handled on windowqueue level */
|
|
|
|
else if (sfile->op) {
|
|
|
|
wmOperator *op = sfile->op;
|
|
|
|
|
2019-04-29 14:14:14 +10:00
|
|
|
/* When used as a macro, for double-click, to prevent closing when double-clicking on item. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (RNA_boolean_get(exec_op->ptr, "need_active")) {
|
|
|
|
const int numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
int i, active = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < numfiles; i++) {
|
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
|
|
|
|
active = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
if (active == 0) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sfile->op = NULL;
|
|
|
|
|
|
|
|
file_sfile_to_operator_ex(C, op, sfile, filepath);
|
|
|
|
|
|
|
|
if (BLI_exists(sfile->params->dir)) {
|
|
|
|
fsmenu_insert_entry(ED_fsmenu_get(),
|
|
|
|
FS_CATEGORY_RECENT,
|
|
|
|
sfile->params->dir,
|
|
|
|
NULL,
|
2019-12-06 13:10:30 -08:00
|
|
|
ICON_FILE_FOLDER,
|
2019-04-17 06:17:24 +02:00
|
|
|
FS_INSERT_SAVE | FS_INSERT_FIRST);
|
|
|
|
}
|
|
|
|
|
2020-03-07 13:23:26 +11:00
|
|
|
BLI_join_dirfile(filepath,
|
|
|
|
sizeof(filepath),
|
|
|
|
BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, NULL),
|
|
|
|
BLENDER_BOOKMARK_FILE);
|
2019-04-17 06:17:24 +02:00
|
|
|
fsmenu_write_file(ED_fsmenu_get(), filepath);
|
|
|
|
WM_event_fileselect_event(wm, op, EVT_FILESELECT_EXEC);
|
|
|
|
}
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-01-28 11:27:25 +00:00
|
|
|
}
|
|
|
|
|
2020-08-07 11:36:37 +02:00
|
|
|
static int file_exec_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
|
|
|
{
|
|
|
|
ARegion *region = CTX_wm_region(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
|
|
|
|
if (!ED_fileselect_layout_is_inside_pt(
|
|
|
|
sfile->layout, ®ion->v2d, event->mval[0], event->mval[1])) {
|
|
|
|
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
return file_exec(C, op);
|
|
|
|
}
|
|
|
|
|
2009-09-04 04:29:54 +00:00
|
|
|
void FILE_OT_execute(struct wmOperatorType *ot)
|
2009-01-28 11:27:25 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
2012-03-23 22:31:14 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Execute File Window";
|
|
|
|
ot->description = "Execute selected file";
|
|
|
|
ot->idname = "FILE_OT_execute";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
2020-08-07 11:36:37 +02:00
|
|
|
ot->invoke = file_exec_invoke;
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = file_exec;
|
|
|
|
ot->poll = file_operator_poll;
|
2012-10-08 03:33:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* properties */
|
|
|
|
prop = RNA_def_boolean(ot->srna,
|
|
|
|
"need_active",
|
|
|
|
0,
|
|
|
|
"Need Active",
|
|
|
|
"Only execute if there's an active selected file in the file list");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2009-01-28 11:27:25 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Refresh File List Operator
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static int file_refresh_exec(bContext *C, wmOperator *UNUSED(unused))
|
|
|
|
{
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
struct FSMenu *fsmenu = ED_fsmenu_get();
|
|
|
|
|
|
|
|
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
|
|
|
|
|
|
|
|
/* refresh system directory menu */
|
|
|
|
fsmenu_refresh_system_category(fsmenu);
|
|
|
|
|
|
|
|
/* Update bookmarks 'valid' state. */
|
|
|
|
fsmenu_refresh_bookmarks_status(wm, fsmenu);
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_refresh(struct wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Refresh Filelist";
|
|
|
|
ot->description = "Refresh the file list";
|
|
|
|
ot->idname = "FILE_OT_refresh";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_refresh_exec;
|
|
|
|
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Navigate Parent Operator
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static int file_parent_exec(bContext *C, wmOperator *UNUSED(unused))
|
2009-02-10 17:53:10 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile->params) {
|
2020-04-07 12:02:21 +10:00
|
|
|
if (BLI_path_parent_dir(sfile->params->dir)) {
|
|
|
|
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_file_change_dir(C);
|
|
|
|
if (sfile->params->recursion_level > 1) {
|
|
|
|
/* Disable 'dirtree' recursion when going up in tree. */
|
|
|
|
sfile->params->recursion_level = 0;
|
|
|
|
filelist_setrecursion(sfile->files, sfile->params->recursion_level);
|
|
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
}
|
|
|
|
}
|
2009-02-10 17:53:10 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-02-10 17:53:10 +00:00
|
|
|
}
|
|
|
|
|
2009-02-14 14:25:48 +00:00
|
|
|
void FILE_OT_parent(struct wmOperatorType *ot)
|
2009-02-10 17:53:10 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Parent File";
|
|
|
|
ot->description = "Move to parent directory";
|
|
|
|
ot->idname = "FILE_OT_parent";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_parent_exec;
|
|
|
|
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
|
2009-02-10 17:53:10 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Navigate Previous Operator
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static int file_previous_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-03-12 06:40:03 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2012-05-18 12:49:25 +00:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
if (sfile->params) {
|
|
|
|
if (!sfile->folders_next) {
|
|
|
|
sfile->folders_next = folderlist_new();
|
|
|
|
}
|
2009-07-07 07:25:44 +00:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
|
|
|
|
folderlist_popdir(sfile->folders_prev, sfile->params->dir);
|
|
|
|
folderlist_pushdir(sfile->folders_next, sfile->params->dir);
|
2019-05-15 16:20:14 +02:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
ED_file_change_dir(C);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
2009-07-07 07:25:44 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-07-07 07:25:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_previous(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Previous Folder";
|
|
|
|
ot->description = "Move to previous folder";
|
|
|
|
ot->idname = "FILE_OT_previous";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_previous_exec;
|
|
|
|
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
|
2009-07-07 07:25:44 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Navigate Next Operator
|
|
|
|
* \{ */
|
|
|
|
|
|
|
|
static int file_next_exec(bContext *C, wmOperator *UNUSED(unused))
|
2009-07-07 07:25:44 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
if (sfile->params) {
|
2019-04-22 09:19:45 +10:00
|
|
|
if (!sfile->folders_next) {
|
2019-04-17 06:17:24 +02:00
|
|
|
sfile->folders_next = folderlist_new();
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2009-07-07 07:25:44 +00:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
|
|
|
|
folderlist_popdir(sfile->folders_next, sfile->params->dir);
|
|
|
|
|
|
|
|
// update folders_prev so we can check for it in folderlist_clear_next()
|
|
|
|
folderlist_pushdir(sfile->folders_prev, sfile->params->dir);
|
2009-07-07 07:25:44 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ED_file_change_dir(C);
|
|
|
|
}
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
2009-03-12 06:40:03 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-07-07 07:25:44 +00:00
|
|
|
}
|
2009-03-12 06:40:03 +00:00
|
|
|
|
2009-07-07 07:25:44 +00:00
|
|
|
void FILE_OT_next(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Next Folder";
|
|
|
|
ot->description = "Move to next folder";
|
|
|
|
ot->idname = "FILE_OT_next";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_next_exec;
|
|
|
|
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
|
2009-03-12 06:40:03 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
2009-07-07 07:25:44 +00:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Smooth Scroll Operator
|
|
|
|
* \{ */
|
2009-03-12 06:40:03 +00:00
|
|
|
|
2010-05-08 21:02:22 +00:00
|
|
|
/* only meant for timer usage */
|
2013-03-13 09:03:46 +00:00
|
|
|
static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
|
2010-05-08 21:02:22 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2020-04-03 12:51:03 +02:00
|
|
|
ARegion *region, *region_ctx = CTX_wm_region(C);
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
const bool is_horizontal = (sfile->layout->flag & FILE_LAYOUT_HOR) != 0;
|
2019-04-17 06:17:24 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
/* escape if not our timer */
|
2019-04-22 09:19:45 +10:00
|
|
|
if (sfile->smoothscroll_timer == NULL || sfile->smoothscroll_timer != event->customdata) {
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_PASS_THROUGH;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
const int numfiles = filelist_files_ensure(sfile->files);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* Due to async nature of file listing, we may execute this code before `file_refresh()`
|
2019-04-22 00:18:34 +10:00
|
|
|
* editing entry is available in our listing,
|
|
|
|
* so we also have to handle switching to rename mode here. */
|
2019-04-17 06:17:24 +02:00
|
|
|
FileSelectParams *params = ED_fileselect_get_params(sfile);
|
|
|
|
if ((params->rename_flag &
|
|
|
|
(FILE_PARAMS_RENAME_PENDING | FILE_PARAMS_RENAME_POSTSCROLL_PENDING)) != 0) {
|
|
|
|
file_params_renamefile_activate(sfile, params);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* check if we are editing a name */
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
int edit_idx = -1;
|
2019-09-08 00:12:26 +10:00
|
|
|
for (i = 0; i < numfiles; i++) {
|
2019-04-17 06:17:24 +02:00
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL) &
|
|
|
|
(FILE_SEL_EDITING | FILE_SEL_HIGHLIGHTED)) {
|
|
|
|
edit_idx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if we are not editing, we are done */
|
|
|
|
if (edit_idx == -1) {
|
2019-04-22 00:18:34 +10:00
|
|
|
/* Do not invalidate timer if filerename is still pending,
|
|
|
|
* we might still be building the filelist and yet have to find edited entry. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (params->rename_flag == 0) {
|
|
|
|
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
|
|
|
|
sfile->smoothscroll_timer = NULL;
|
|
|
|
}
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* we need the correct area for scrolling */
|
2020-04-03 13:25:03 +02:00
|
|
|
region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
|
2020-03-06 16:56:42 +01:00
|
|
|
if (!region || region->regiontype != RGN_TYPE_WINDOW) {
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
|
|
|
|
sfile->smoothscroll_timer = NULL;
|
|
|
|
return OPERATOR_PASS_THROUGH;
|
|
|
|
}
|
|
|
|
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
/* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line
|
|
|
|
* in vertical layout).
|
|
|
|
*/
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
/* Scroll offset is the first file in the row/column we are editing in. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile->scroll_offset == 0) {
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
sfile->scroll_offset = (edit_idx / items_block_size) * items_block_size;
|
|
|
|
}
|
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
const int numfiles_layout = ED_fileselect_layout_numfiles(sfile->layout, region);
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
const int first_visible_item = ED_fileselect_layout_offset(
|
2020-03-06 16:56:42 +01:00
|
|
|
sfile->layout, (int)region->v2d.cur.xmin, (int)-region->v2d.cur.ymax);
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
const int last_visible_item = first_visible_item + numfiles_layout + 1;
|
|
|
|
|
|
|
|
/* Note: the special case for vertical layout is because filename is at the bottom of items then,
|
|
|
|
* so we artificially move current row back one step, to ensure we show bottom of
|
|
|
|
* active item rather than its top (important in case visible height is low). */
|
|
|
|
const int middle_offset = max_ii(
|
|
|
|
0, (first_visible_item + last_visible_item) / 2 - (is_horizontal ? 0 : items_block_size));
|
|
|
|
|
|
|
|
const int min_middle_offset = numfiles_layout / 2;
|
|
|
|
const int max_middle_offset = ((numfiles / items_block_size) * items_block_size +
|
|
|
|
((numfiles % items_block_size) != 0 ? items_block_size : 0)) -
|
|
|
|
(numfiles_layout / 2);
|
|
|
|
/* Actual (physical) scrolling info, in pixels, used to detect whether we are fully at the
|
2019-07-07 15:38:41 +10:00
|
|
|
* beginning/end of the view. */
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
/* Note that there is a weird glitch, that sometimes tot rctf is smaller than cur rctf...
|
|
|
|
* that is why we still need to keep the min/max_middle_offset checks too. :( */
|
2020-03-06 16:56:42 +01:00
|
|
|
const float min_tot_scroll = is_horizontal ? region->v2d.tot.xmin : -region->v2d.tot.ymax;
|
|
|
|
const float max_tot_scroll = is_horizontal ? region->v2d.tot.xmax : -region->v2d.tot.ymin;
|
|
|
|
const float min_curr_scroll = is_horizontal ? region->v2d.cur.xmin : -region->v2d.cur.ymax;
|
|
|
|
const float max_curr_scroll = is_horizontal ? region->v2d.cur.xmax : -region->v2d.cur.ymin;
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
|
|
|
|
/* Check if we have reached our final scroll position. */
|
|
|
|
/* Filelist has to be ready, otherwise it makes no sense to stop scrolling yet. */
|
|
|
|
const bool is_ready = filelist_is_ready(sfile->files);
|
2019-07-07 15:38:41 +10:00
|
|
|
/* Edited item must be in the 'middle' of shown area (kind of approximated).
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
* Note that we have to do the check in 'block space', not in 'item space' here. */
|
|
|
|
const bool is_centered = (abs(middle_offset / items_block_size -
|
|
|
|
sfile->scroll_offset / items_block_size) == 0);
|
2019-07-07 15:38:41 +10:00
|
|
|
/* OR edited item must be towards the beginning, and we are scrolled fully to the start. */
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
const bool is_full_start = ((sfile->scroll_offset < min_middle_offset) &&
|
|
|
|
(min_curr_scroll - min_tot_scroll < 1.0f) &&
|
|
|
|
(middle_offset - min_middle_offset < items_block_size));
|
|
|
|
/* OR edited item must be towards the end, and we are scrolled fully to the end.
|
2019-07-07 15:38:41 +10:00
|
|
|
* This one is crucial (unlike the one for the beginning), because without it we won't scroll
|
2019-08-01 13:53:25 +10:00
|
|
|
* fully to the end, and last column or row will end up only partially drawn. */
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
const bool is_full_end = ((sfile->scroll_offset > max_middle_offset) &&
|
|
|
|
(max_tot_scroll - max_curr_scroll < 1.0f) &&
|
|
|
|
(max_middle_offset - middle_offset < items_block_size));
|
|
|
|
|
|
|
|
if (is_ready && (is_centered || is_full_start || is_full_end)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), sfile->smoothscroll_timer);
|
|
|
|
sfile->smoothscroll_timer = NULL;
|
2019-04-29 14:14:14 +10:00
|
|
|
/* Post-scroll (after rename has been validated by user) is done,
|
|
|
|
* rename process is totally finished, cleanup. */
|
2019-04-17 06:17:24 +02:00
|
|
|
if ((params->rename_flag & FILE_PARAMS_RENAME_POSTSCROLL_ACTIVE) != 0) {
|
|
|
|
params->renamefile[0] = '\0';
|
|
|
|
params->rename_flag = 0;
|
|
|
|
}
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
/* Temporarily set context to the main window region,
|
|
|
|
* so that the pan operator works. */
|
2020-03-06 16:56:42 +01:00
|
|
|
CTX_wm_region_set(C, region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* scroll one step in the desired direction */
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
PointerRNA op_ptr;
|
|
|
|
int deltax = 0;
|
|
|
|
int deltay = 0;
|
|
|
|
|
|
|
|
/* We adjust speed of scrolling to avoid tens of seconds of it in e.g. directories with tens of
|
|
|
|
* thousands of folders... See T65782. */
|
|
|
|
/* This will slow down scrolling when approaching final goal, also avoids going too far and
|
|
|
|
* having to bounce back... */
|
|
|
|
|
|
|
|
/* Number of blocks (columns in horizontal layout, rows otherwise) between current middle of
|
|
|
|
* screen, and final goal position. */
|
|
|
|
const int diff_offset = sfile->scroll_offset / items_block_size -
|
|
|
|
middle_offset / items_block_size;
|
|
|
|
/* convert diff_offset into pixels. */
|
|
|
|
const int diff_offset_delta = abs(diff_offset) *
|
|
|
|
(is_horizontal ?
|
|
|
|
sfile->layout->tile_w + 2 * sfile->layout->tile_border_x :
|
|
|
|
sfile->layout->tile_h + 2 * sfile->layout->tile_border_y);
|
|
|
|
const int scroll_delta = max_ii(2, diff_offset_delta / 15);
|
|
|
|
|
|
|
|
if (diff_offset < 0) {
|
|
|
|
if (is_horizontal) {
|
|
|
|
deltax = -scroll_delta;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
deltay = scroll_delta;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
if (is_horizontal) {
|
|
|
|
deltax = scroll_delta;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
else {
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
deltay = -scroll_delta;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
}
|
File Browser: Various fixes and enhancements to 'autoscroll to item' feature.
Initial trigger to this work was T65782, requesting faster autoscroll
when current folder contains thousands of items. That was a fairly
simple change, just needed to make scrolling steps variable based on
'distance' between current position and desired one.
But several other issues showed up while working on this, among the most
annoying ones, the scrolltimer could keep running forever in some cases,
failing to detect properly an 'end condition', we could even get some
'bouncing' in extreme corner cases, edited item was not always properly
visible in the end, etc.
So as usual with UI, this ended up in a frustrating equilibrium game of
finding the optimal solution among several tradeof, taking unexpected
large amount of time... At least new code seems to work OK in
all possible (reasonable) cases, that will do for now.
2019-06-18 21:44:14 +02:00
|
|
|
WM_operator_properties_create(&op_ptr, "VIEW2D_OT_pan");
|
|
|
|
RNA_int_set(&op_ptr, "deltax", deltax);
|
|
|
|
RNA_int_set(&op_ptr, "deltay", deltay);
|
|
|
|
|
|
|
|
WM_operator_name_call(C, "VIEW2D_OT_pan", WM_OP_EXEC_DEFAULT, &op_ptr);
|
|
|
|
WM_operator_properties_free(&op_ptr);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2020-03-06 16:56:42 +01:00
|
|
|
ED_region_tag_redraw(region);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* and restore context */
|
2020-04-03 12:51:03 +02:00
|
|
|
CTX_wm_region_set(C, region_ctx);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2010-05-08 21:02:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_smoothscroll(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Smooth Scroll";
|
|
|
|
ot->idname = "FILE_OT_smoothscroll";
|
|
|
|
ot->description = "Smooth scroll to make editable file visible";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = file_smoothscroll_invoke;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->poll = ED_operator_file_active;
|
2010-05-08 21:02:22 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name File Selector Drop Operator
|
|
|
|
* \{ */
|
|
|
|
|
2015-11-04 14:24:46 +01:00
|
|
|
static int filepath_drop_exec(bContext *C, wmOperator *op)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile) {
|
|
|
|
char filepath[FILE_MAX];
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_string_get(op->ptr, "filepath", filepath);
|
|
|
|
if (!BLI_exists(filepath)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "File does not exist");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
file_sfile_filepath_set(sfile, filepath);
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile->op) {
|
|
|
|
file_sfile_to_operator(C, sfile->op, sfile);
|
|
|
|
file_draw_check(C);
|
|
|
|
}
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_CANCELLED;
|
2015-11-04 14:24:46 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_filepath_drop(wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->name = "File Selector Drop";
|
|
|
|
ot->idname = "FILE_OT_filepath_drop";
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = filepath_drop_exec;
|
|
|
|
ot->poll = WM_operator_winactive;
|
2015-11-04 14:24:46 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
RNA_def_string_file_path(ot->srna, "filepath", "Path", FILE_MAX, "", "");
|
2015-11-04 14:24:46 +01:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name New Directory Operator
|
|
|
|
* \{ */
|
|
|
|
|
2019-04-22 00:18:34 +10:00
|
|
|
/**
|
|
|
|
* Create a new, non-existing folder name, returns 1 if successful, 0 if name couldn't be created.
|
|
|
|
* The actual name is returned in 'name', 'folder' contains the complete path,
|
|
|
|
* including the new folder name.
|
2012-03-03 16:31:46 +00:00
|
|
|
*/
|
2012-06-18 13:01:24 +00:00
|
|
|
static int new_folder_path(const char *parent, char *folder, char *name)
|
2009-07-10 17:05:04 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
int i = 1;
|
|
|
|
int len = 0;
|
2009-12-07 23:47:37 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(name, "New Folder", FILE_MAXFILE);
|
|
|
|
BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
|
|
|
|
/* check whether folder with the name already exists, in this case
|
|
|
|
* add number to the name. Check length of generated name to avoid
|
|
|
|
* crazy case of huge number of folders each named 'New Folder (x)' */
|
|
|
|
while (BLI_exists(folder) && (len < FILE_MAXFILE)) {
|
|
|
|
len = BLI_snprintf(name, FILE_MAXFILE, "New Folder(%d)", i);
|
|
|
|
BLI_join_dirfile(folder, FILE_MAX, parent, name); /* XXX, not real length */
|
|
|
|
i++;
|
|
|
|
}
|
2009-07-10 17:05:04 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return (len < FILE_MAXFILE);
|
2009-12-07 23:47:37 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
static int file_directory_new_exec(bContext *C, wmOperator *op)
|
2009-12-07 23:47:37 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char name[FILE_MAXFILE];
|
|
|
|
char path[FILE_MAX];
|
|
|
|
bool generate_name = true;
|
|
|
|
PropertyRNA *prop;
|
|
|
|
|
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2019-09-06 11:21:47 +02:00
|
|
|
const bool do_diropen = RNA_boolean_get(op->ptr, "open");
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
if (!sfile->params) {
|
|
|
|
BKE_report(op->reports, RPT_WARNING, "No parent directory given");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
path[0] = '\0';
|
|
|
|
|
|
|
|
if ((prop = RNA_struct_find_property(op->ptr, "directory"))) {
|
|
|
|
RNA_property_string_get(op->ptr, prop, path);
|
|
|
|
if (path[0] != '\0') {
|
|
|
|
generate_name = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (generate_name) {
|
|
|
|
/* create a new, non-existing folder name */
|
|
|
|
if (!new_folder_path(sfile->params->dir, path, name)) {
|
|
|
|
BKE_report(op->reports, RPT_ERROR, "Could not create new folder name");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else { /* We assume we are able to generate a valid name! */
|
|
|
|
char org_path[FILE_MAX];
|
|
|
|
|
|
|
|
BLI_strncpy(org_path, path, sizeof(org_path));
|
|
|
|
if (BLI_path_make_safe(path)) {
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_WARNING,
|
|
|
|
"'%s' given path is OS-invalid, creating '%s' path instead",
|
|
|
|
org_path,
|
|
|
|
path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* create the file */
|
|
|
|
errno = 0;
|
|
|
|
if (!BLI_dir_create_recursive(path) ||
|
|
|
|
/* Should no more be needed,
|
|
|
|
* now that BLI_dir_create_recursive returns a success state - but kept just in case. */
|
|
|
|
!BLI_exists(path)) {
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Could not create new folder: %s",
|
|
|
|
errno ? strerror(errno) : "unknown error");
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2019-09-06 11:21:47 +02:00
|
|
|
/* If we don't enter the directory directly, remember file to jump into editing. */
|
|
|
|
if (do_diropen == false) {
|
|
|
|
BLI_strncpy(sfile->params->renamefile, name, FILE_MAXFILE);
|
|
|
|
sfile->params->rename_flag = FILE_PARAMS_RENAME_PENDING;
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* set timer to smoothly view newly generated file */
|
|
|
|
/* max 30 frs/sec */
|
|
|
|
if (sfile->smoothscroll_timer != NULL) {
|
2020-03-13 17:34:21 +01:00
|
|
|
WM_event_remove_timer(wm, CTX_wm_window(C), sfile->smoothscroll_timer);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
sfile->smoothscroll_timer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER1, 1.0 / 1000.0);
|
|
|
|
sfile->scroll_offset = 0;
|
|
|
|
|
|
|
|
/* reload dir to make sure we're seeing what's in the directory */
|
2020-03-13 17:34:21 +01:00
|
|
|
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-09-06 11:21:47 +02:00
|
|
|
if (do_diropen) {
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir));
|
|
|
|
ED_file_change_dir(C);
|
|
|
|
}
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-07-10 17:05:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_directory_new(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
PropertyRNA *prop;
|
2012-10-08 03:33:02 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Create New Directory";
|
|
|
|
ot->description = "Create a new directory";
|
|
|
|
ot->idname = "FILE_OT_directory_new";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
2019-09-06 11:06:32 +02:00
|
|
|
ot->invoke = WM_operator_confirm_or_exec;
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = file_directory_new_exec;
|
|
|
|
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
|
2010-11-06 16:09:12 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
prop = RNA_def_string_dir_path(
|
|
|
|
ot->srna, "directory", NULL, FILE_MAX, "Directory", "Name of new directory");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
|
|
|
prop = RNA_def_boolean(ot->srna, "open", false, "Open", "Open new directory");
|
|
|
|
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
2019-09-06 11:06:32 +02:00
|
|
|
WM_operator_properties_confirm_or_exec(ot);
|
2009-07-10 17:05:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Refresh File List Operator
|
|
|
|
* \{ */
|
|
|
|
|
2015-07-14 18:48:51 +02:00
|
|
|
/* TODO This should go to BLI_path_utils. */
|
2010-11-06 16:09:12 +00:00
|
|
|
static void file_expand_directory(bContext *C)
|
2009-07-10 17:05:04 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
|
|
|
|
if (sfile->params) {
|
|
|
|
if (BLI_path_is_rel(sfile->params->dir)) {
|
|
|
|
/* Use of 'default' folder here is just to avoid an error message on '//' prefix. */
|
|
|
|
BLI_path_abs(sfile->params->dir,
|
|
|
|
G.relbase_valid ? BKE_main_blendfile_path(bmain) : BKE_appdir_folder_default());
|
|
|
|
}
|
|
|
|
else if (sfile->params->dir[0] == '~') {
|
|
|
|
char tmpstr[sizeof(sfile->params->dir) - 1];
|
|
|
|
BLI_strncpy(tmpstr, sfile->params->dir + 1, sizeof(tmpstr));
|
|
|
|
BLI_join_dirfile(
|
|
|
|
sfile->params->dir, sizeof(sfile->params->dir), BKE_appdir_folder_default(), tmpstr);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (sfile->params->dir[0] == '\0')
|
2012-01-30 10:04:27 +00:00
|
|
|
#ifndef WIN32
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
|
|
|
sfile->params->dir[0] = '/';
|
|
|
|
sfile->params->dir[1] = '\0';
|
|
|
|
}
|
2012-01-30 10:04:27 +00:00
|
|
|
#else
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
|
|
|
get_default_root(sfile->params->dir);
|
|
|
|
}
|
|
|
|
/* change "C:" --> "C:\", [#28102] */
|
|
|
|
else if ((isalpha(sfile->params->dir[0]) && (sfile->params->dir[1] == ':')) &&
|
|
|
|
(sfile->params->dir[2] == '\0')) {
|
|
|
|
sfile->params->dir[2] = '\\';
|
|
|
|
sfile->params->dir[3] = '\0';
|
|
|
|
}
|
|
|
|
else if (BLI_path_is_unc(sfile->params->dir)) {
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_normalize_unc(sfile->params->dir, FILE_MAX_LIBEXTRA);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-07-10 19:52:00 +00:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2010-11-06 16:09:12 +00:00
|
|
|
}
|
|
|
|
|
2015-07-14 18:48:51 +02:00
|
|
|
/* TODO check we still need this, it's annoying to have OS-specific code here... :/ */
|
2014-04-21 16:49:35 +02:00
|
|
|
#if defined(WIN32)
|
|
|
|
static bool can_create_dir(const char *dir)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* for UNC paths we need to check whether the parent of the new
|
|
|
|
* directory is a proper directory itself and not a share or the
|
|
|
|
* UNC root (server name) itself. Calling BLI_is_dir does this
|
|
|
|
*/
|
|
|
|
if (BLI_path_is_unc(dir)) {
|
|
|
|
char parent[PATH_MAX];
|
|
|
|
BLI_strncpy(parent, dir, PATH_MAX);
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_parent_dir(parent);
|
2019-04-17 06:17:24 +02:00
|
|
|
return BLI_is_dir(parent);
|
|
|
|
}
|
|
|
|
return true;
|
2014-04-21 16:49:35 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-11-22 01:35:38 +01:00
|
|
|
void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UNUSED(arg_but))
|
2010-11-06 16:09:12 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
|
|
|
|
if (sfile->params) {
|
2019-09-20 20:41:00 +02:00
|
|
|
char old_dir[sizeof(sfile->params->dir)];
|
|
|
|
|
|
|
|
BLI_strncpy(old_dir, sfile->params->dir, sizeof(old_dir));
|
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
file_expand_directory(C);
|
|
|
|
|
|
|
|
/* special case, user may have pasted a filepath into the directory */
|
|
|
|
if (!filelist_is_dir(sfile->files, sfile->params->dir)) {
|
|
|
|
char tdir[FILE_MAX_LIBEXTRA];
|
|
|
|
char *group, *name;
|
|
|
|
|
|
|
|
if (BLI_is_file(sfile->params->dir)) {
|
|
|
|
char path[sizeof(sfile->params->dir)];
|
|
|
|
BLI_strncpy(path, sfile->params->dir, sizeof(path));
|
|
|
|
BLI_split_dirfile(path,
|
|
|
|
sfile->params->dir,
|
|
|
|
sfile->params->file,
|
|
|
|
sizeof(sfile->params->dir),
|
|
|
|
sizeof(sfile->params->file));
|
|
|
|
}
|
|
|
|
else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) {
|
|
|
|
if (group) {
|
|
|
|
BLI_path_append(tdir, sizeof(tdir), group);
|
|
|
|
}
|
|
|
|
BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir));
|
|
|
|
if (name) {
|
|
|
|
BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sfile->params->file[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), sfile->params->dir);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
if (filelist_is_dir(sfile->files, sfile->params->dir)) {
|
2019-09-20 20:41:00 +02:00
|
|
|
if (!STREQ(sfile->params->dir, old_dir)) { /* Avoids flickering when nothing's changed. */
|
|
|
|
/* if directory exists, enter it immediately */
|
|
|
|
ED_file_change_dir(C);
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
/* don't do for now because it selects entire text instead of
|
|
|
|
* placing cursor at the end */
|
|
|
|
/* UI_textbutton_activate_but(C, but); */
|
|
|
|
}
|
2014-04-21 16:49:35 +02:00
|
|
|
#if defined(WIN32)
|
2019-04-17 06:17:24 +02:00
|
|
|
else if (!can_create_dir(sfile->params->dir)) {
|
|
|
|
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
|
2019-04-22 09:19:45 +10:00
|
|
|
if (lastdir) {
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2014-04-21 16:49:35 +02:00
|
|
|
#endif
|
2019-04-17 06:17:24 +02:00
|
|
|
else {
|
|
|
|
const char *lastdir = folderlist_peeklastdir(sfile->folders_prev);
|
|
|
|
char tdir[FILE_MAX_LIBEXTRA];
|
|
|
|
|
|
|
|
/* If we are 'inside' a blend library, we cannot do anything... */
|
|
|
|
if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) {
|
|
|
|
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* if not, ask to create it and enter if confirmed */
|
|
|
|
wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false);
|
|
|
|
PointerRNA ptr;
|
|
|
|
WM_operator_properties_create_ptr(&ptr, ot);
|
|
|
|
RNA_string_set(&ptr, "directory", sfile->params->dir);
|
|
|
|
RNA_boolean_set(&ptr, "open", true);
|
2019-09-06 11:06:32 +02:00
|
|
|
/* Enable confirmation prompt, else it's too easy to accidentaly create new directories. */
|
|
|
|
RNA_boolean_set(&ptr, "confirm", true);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (lastdir) {
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir));
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
|
|
|
WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr);
|
|
|
|
WM_operator_properties_free(&ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
}
|
2013-11-22 14:35:34 +01:00
|
|
|
}
|
|
|
|
|
2013-11-22 01:35:38 +01:00
|
|
|
void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg_but)
|
2009-07-10 17:05:04 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
Main *bmain = CTX_data_main(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
uiBut *but = arg_but;
|
|
|
|
char matched_file[FILE_MAX];
|
|
|
|
char filepath[sizeof(sfile->params->dir)];
|
2013-11-22 14:35:34 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile->params) {
|
|
|
|
int matches;
|
|
|
|
matched_file[0] = '\0';
|
|
|
|
filepath[0] = '\0';
|
2013-11-22 14:35:34 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
file_expand_directory(C);
|
2013-11-22 01:35:38 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
matches = file_select_match(sfile, sfile->params->file, matched_file);
|
2013-11-22 01:35:38 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* *After* file_select_match! */
|
|
|
|
BLI_filename_make_safe(sfile->params->file);
|
2015-09-13 08:20:48 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (matches) {
|
|
|
|
/* replace the pattern (or filename that the user typed in,
|
|
|
|
* with the first selected file of the match */
|
|
|
|
BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file));
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
}
|
2013-11-22 14:35:34 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (matches == 1) {
|
|
|
|
BLI_join_dirfile(
|
|
|
|
filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file);
|
2013-11-22 14:35:34 +01:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* if directory, open it and empty filename field */
|
|
|
|
if (filelist_is_dir(sfile->files, filepath)) {
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_normalize_dir(BKE_main_blendfile_path(bmain), filepath);
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir));
|
|
|
|
sfile->params->file[0] = '\0';
|
|
|
|
ED_file_change_dir(C);
|
|
|
|
UI_textbutton_activate_but(C, but);
|
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (matches > 1) {
|
|
|
|
file_draw_check(C);
|
|
|
|
}
|
|
|
|
}
|
2013-11-22 14:35:34 +01:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Toggle Show Hidden Files Operator
|
|
|
|
* \{ */
|
2009-03-12 06:40:03 +00:00
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static int file_hidedot_exec(bContext *C, wmOperator *UNUSED(unused))
|
2009-06-30 18:29:30 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile->params) {
|
|
|
|
sfile->params->flag ^= FILE_HIDE_DOT;
|
2020-03-13 17:34:21 +01:00
|
|
|
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-06-30 18:29:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_hidedot(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Toggle Hide Dot Files";
|
|
|
|
ot->description = "Toggle hide hidden dot files";
|
|
|
|
ot->idname = "FILE_OT_hidedot";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_hidedot_exec;
|
|
|
|
ot->poll = ED_operator_file_active; /* <- important, handler is on window level */
|
2009-06-30 18:29:30 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Increment Filename Operator
|
|
|
|
* \{ */
|
|
|
|
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
static bool file_filenum_poll(bContext *C)
|
|
|
|
{
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
|
|
|
|
if (!ED_operator_file_active(C)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-16 18:14:23 +02:00
|
|
|
return sfile->params && (sfile->params->flag & FILE_CHECK_EXISTING);
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
}
|
|
|
|
|
2015-10-16 04:57:52 +11:00
|
|
|
/**
|
2020-04-07 12:02:21 +10:00
|
|
|
* Looks for a string of digits within name (using BLI_path_sequence_decode) and adjusts it by add.
|
2015-10-16 04:57:52 +11:00
|
|
|
*/
|
|
|
|
static void filenum_newname(char *name, size_t name_size, int add)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
char head[FILE_MAXFILE], tail[FILE_MAXFILE];
|
|
|
|
char name_temp[FILE_MAXFILE];
|
|
|
|
int pic;
|
2020-04-03 16:21:24 +11:00
|
|
|
ushort digits;
|
2015-10-16 04:57:52 +11:00
|
|
|
|
2020-04-07 12:02:21 +10:00
|
|
|
pic = BLI_path_sequence_decode(name, head, tail, &digits);
|
2015-10-16 04:57:52 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* are we going from 100 -> 99 or from 10 -> 9 */
|
|
|
|
if (add < 0 && digits > 0) {
|
|
|
|
int i, exp;
|
|
|
|
exp = 1;
|
|
|
|
for (i = digits; i > 1; i--) {
|
|
|
|
exp *= 10;
|
|
|
|
}
|
|
|
|
if (pic >= exp && (pic + add) < exp) {
|
|
|
|
digits--;
|
|
|
|
}
|
|
|
|
}
|
2015-10-16 04:57:52 +11:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
pic += add;
|
2019-04-22 09:19:45 +10:00
|
|
|
if (pic < 0) {
|
2019-04-17 06:17:24 +02:00
|
|
|
pic = 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2020-04-07 12:02:21 +10:00
|
|
|
BLI_path_sequence_encode(name_temp, head, tail, digits, pic);
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(name, name_temp, name_size);
|
2015-10-16 04:57:52 +11:00
|
|
|
}
|
|
|
|
|
2011-02-14 17:55:27 +00:00
|
|
|
static int file_filenum_exec(bContext *C, wmOperator *op)
|
2009-07-05 22:26:43 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
int inc = RNA_int_get(op->ptr, "increment");
|
|
|
|
if (sfile->params && (inc != 0)) {
|
|
|
|
filenum_newname(sfile->params->file, sizeof(sfile->params->file), inc);
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
file_draw_check(C);
|
|
|
|
// WM_event_add_notifier(C, NC_WINDOW, NULL);
|
|
|
|
}
|
2009-07-05 22:26:43 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-07-05 22:26:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_filenum(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Increment Number in Filename";
|
|
|
|
ot->description = "Increment number in filename";
|
|
|
|
ot->idname = "FILE_OT_filenum";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_filenum_exec;
|
UI: File Browser Design Overhaul
This is a general redesign of the File Browser GUI and interaction
methods. For screenshots, check patch D5601.
Main changes in short:
* File Browser as floating window
* New layout of regions
* Popovers for view and filter options
* Vertical list view with interactive column header
* New and updated icons
* Keymap consistency fixes
* Many tweaks and fixes to the drawing of views
----
General:
* The file browser now opens as temporary floating window. It closes on
Esc. The header is hidden then.
* When the file browser is opened as regular editor, the header remains
visible.
* All file browser regions are now defined in Python (the button
layout).
* Adjusted related operator UI names.
Keymap:
Keymap is now consistent with other list-based views in Blender, such as
the Outliner.
* Left click to select, double-click to open
* Right-click context menus
* Shift-click to fill selection
* Ctrl-click to extend selection
Operator options:
These previously overlapped with the source list, which caused numerous
issues with resizing and presenting many settings in a small panel area.
It was also generally inconsistent with Blender.
* Moved to new sidebar, which can easily be shown or hidden using a
prominent Options toggle.
* IO operators have new layouts to match this new sidebar, using
sub-panels. This will have to be committed separately (Add-on
repository).
* If operators want to show the options by default, they have the option
to do so (see `WM_FILESEL_SHOW_PROPS`, `hide_props_region`), otherwise
they are hidden by default.
General Layout:
The layout has been changed to be simpler, more standard, and fits
better in with Blender 2.8.
* More conventional layout (file path at top, file name at the bottom,
execute/cancel buttons in bottom right).
* Use of popovers to group controls, and allow for more descriptive
naming.
* Search box is always live now, just like Outliner.
Views:
* Date Modified column combines both date and time, also uses user
friendly strings for recent dates (i.e. "Yesterday", "Today").
* Details columns (file size, modification date/time) are now toggleable
for all display types, they are not hardcoded per display type.
* File sizes now show as B, KB, MB, ... rather than B, KiB, MiB, … They
are now also calculated using base 10 of course.
* Option to sort in inverse order.
Vertical List View:
* This view now used a much simpler single vertical list with columns
for information.
* Users can click on the headers of these columns to order by that
category, and click again to reverse the ordering.
Icons:
* Updated icons by Jendrzych, with better centering.
* Files and folders have new icons in Icon view.
* Both files and folders have reworked superimposed icons that show
users the file/folder type.
* 3D file documents correctly use the 3d file icon, which was unused
previously.
* Workspaces now show their icon on Link/Append - also when listed in
the Outliner.
Minor Python-API breakage:
* `bpy.types.FileSelectParams.display_type`: `LIST_SHORT` and
`LIST_LONG` are replaced by `LIST_VERTICAL` and `LIST_HORIZONTAL`.
Removes the feature where directories would automatically be created if
they are entered into the file path text button, but don't exist. We
were not sure if users use it enough to keep it. We can definitely bring
it back.
----
//Combined effort by @billreynish, @harley, @jendrzych, my university
colleague Brian Meisenheimer and myself.//
Differential Revision: https://developer.blender.org/D5601
Reviewers: Brecht, Bastien
2019-09-03 15:43:38 +02:00
|
|
|
ot->poll = file_filenum_poll;
|
2009-07-05 22:26:43 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* props */
|
|
|
|
RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100);
|
2009-07-09 19:49:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Rename File/Directory Operator
|
|
|
|
* \{ */
|
|
|
|
|
2019-10-14 16:21:17 +02:00
|
|
|
static void file_rename_state_activate(SpaceFile *sfile, int file_idx, bool require_selected)
|
2009-07-26 18:52:27 +00:00
|
|
|
{
|
2019-10-14 16:21:17 +02:00
|
|
|
const int numfiles = filelist_files_ensure(sfile->files);
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-10-14 21:05:38 +02:00
|
|
|
if ((file_idx >= 0) && (file_idx < numfiles)) {
|
2019-10-14 16:21:17 +02:00
|
|
|
FileDirEntry *file = filelist_file(sfile->files, file_idx);
|
|
|
|
|
|
|
|
if ((require_selected == false) ||
|
|
|
|
(filelist_entry_select_get(sfile->files, file, CHECK_ALL) & FILE_SEL_SELECTED)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
filelist_entry_select_index_set(
|
2019-10-14 16:21:17 +02:00
|
|
|
sfile->files, file_idx, FILE_SEL_ADD, FILE_SEL_EDITING, CHECK_ALL);
|
2019-04-17 06:17:24 +02:00
|
|
|
BLI_strncpy(sfile->params->renamefile, file->relpath, FILE_MAXFILE);
|
2019-04-22 00:18:34 +10:00
|
|
|
/* We can skip the pending state,
|
|
|
|
* as we can directly set FILE_SEL_EDITING on the expected entry here. */
|
2019-04-17 06:17:24 +02:00
|
|
|
sfile->params->rename_flag = FILE_PARAMS_RENAME_ACTIVE;
|
|
|
|
}
|
2019-10-14 16:21:17 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int file_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
|
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-10-14 16:21:17 +02:00
|
|
|
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
|
|
|
|
|
|
|
|
if (sfile->params) {
|
|
|
|
file_rename_state_activate(sfile, sfile->params->active_file, true);
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2009-07-26 18:52:27 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-07-26 18:52:27 +00:00
|
|
|
}
|
|
|
|
|
2019-10-14 16:21:17 +02:00
|
|
|
static int file_rename_exec(bContext *C, wmOperator *UNUSED(op))
|
2009-09-12 19:54:39 +00:00
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
2019-10-14 16:21:17 +02:00
|
|
|
SpaceFile *sfile = (SpaceFile *)CTX_wm_space_data(C);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-10-14 16:21:17 +02:00
|
|
|
if (sfile->params) {
|
|
|
|
file_rename_state_activate(sfile, sfile->params->highlight_file, false);
|
2020-04-03 13:25:03 +02:00
|
|
|
ED_area_tag_redraw(area);
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2019-10-14 16:21:17 +02:00
|
|
|
return OPERATOR_FINISHED;
|
2009-09-12 19:54:39 +00:00
|
|
|
}
|
|
|
|
|
2009-07-26 18:52:27 +00:00
|
|
|
void FILE_OT_rename(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Rename File or Directory";
|
|
|
|
ot->description = "Rename file or file directory";
|
|
|
|
ot->idname = "FILE_OT_rename";
|
2009-07-26 18:52:27 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
2019-10-14 16:21:17 +02:00
|
|
|
ot->invoke = file_rename_invoke;
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->exec = file_rename_exec;
|
2019-10-14 16:21:17 +02:00
|
|
|
ot->poll = ED_operator_file_active;
|
2009-07-26 18:52:27 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Delete File Operator
|
|
|
|
* \{ */
|
|
|
|
|
2018-07-02 11:47:00 +02:00
|
|
|
static bool file_delete_poll(bContext *C)
|
2009-07-10 17:05:04 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
bool poll = ED_operator_file_active(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
2009-07-10 17:05:04 +00:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
if (sfile && sfile->params) {
|
|
|
|
char dir[FILE_MAX_LIBEXTRA];
|
|
|
|
int numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
int i;
|
|
|
|
int num_selected = 0;
|
2013-03-24 19:29:49 +00:00
|
|
|
|
2019-04-22 09:19:45 +10:00
|
|
|
if (filelist_islibrary(sfile->files, dir, NULL)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
poll = 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
for (i = 0; i < numfiles; i++) {
|
2019-11-26 18:46:31 +01:00
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
num_selected++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (num_selected <= 0) {
|
|
|
|
poll = 0;
|
|
|
|
}
|
|
|
|
}
|
2019-04-22 09:19:45 +10:00
|
|
|
else {
|
2019-04-17 06:17:24 +02:00
|
|
|
poll = 0;
|
2019-04-22 09:19:45 +10:00
|
|
|
}
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
return poll;
|
2009-07-10 17:05:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
static int file_delete_exec(bContext *C, wmOperator *op)
|
2009-07-10 17:05:04 +00:00
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
wmWindowManager *wm = CTX_wm_manager(C);
|
|
|
|
SpaceFile *sfile = CTX_wm_space_file(C);
|
|
|
|
int numfiles = filelist_files_ensure(sfile->files);
|
|
|
|
|
2019-10-10 10:53:13 +02:00
|
|
|
const char *error_message = NULL;
|
2019-04-17 06:17:24 +02:00
|
|
|
bool report_error = false;
|
|
|
|
errno = 0;
|
2020-03-07 13:49:58 +11:00
|
|
|
for (int i = 0; i < numfiles; i++) {
|
2019-11-26 18:46:31 +01:00
|
|
|
if (filelist_entry_select_index_get(sfile->files, i, CHECK_ALL)) {
|
2020-03-07 13:49:58 +11:00
|
|
|
FileDirEntry *file = filelist_file(sfile->files, i);
|
|
|
|
char str[FILE_MAX];
|
|
|
|
BLI_join_dirfile(str, sizeof(str), sfile->params->dir, file->relpath);
|
2019-10-10 10:53:13 +02:00
|
|
|
if (BLI_delete_soft(str, &error_message) != 0 || BLI_exists(str)) {
|
2019-04-17 06:17:24 +02:00
|
|
|
report_error = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (report_error) {
|
2019-10-10 10:53:13 +02:00
|
|
|
if (error_message != NULL) {
|
|
|
|
BKE_reportf(op->reports, RPT_ERROR, "Could not delete file or directory: %s", error_message);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
BKE_reportf(op->reports,
|
|
|
|
RPT_ERROR,
|
|
|
|
"Could not delete file or directory: %s",
|
|
|
|
errno ? strerror(errno) : "unknown error");
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
2020-03-13 17:34:21 +01:00
|
|
|
ED_fileselect_clear(wm, CTX_data_scene(C), sfile);
|
2019-04-17 06:17:24 +02:00
|
|
|
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL);
|
|
|
|
|
|
|
|
return OPERATOR_FINISHED;
|
2009-07-10 17:05:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_delete(struct wmOperatorType *ot)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Delete Selected Files";
|
2019-10-10 10:53:13 +02:00
|
|
|
ot->description = "Move selected files to the trash or recycle bin";
|
2019-04-17 06:17:24 +02:00
|
|
|
ot->idname = "FILE_OT_delete";
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* api callbacks */
|
|
|
|
ot->invoke = WM_operator_confirm;
|
|
|
|
ot->exec = file_delete_exec;
|
|
|
|
ot->poll = file_delete_poll; /* <- important, handler is on window level */
|
2009-07-10 17:05:04 +00:00
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Enter Filter Text Operator
|
|
|
|
* \{ */
|
|
|
|
|
2020-02-28 14:33:31 +01:00
|
|
|
static int file_start_filter_exec(bContext *C, wmOperator *UNUSED(op))
|
|
|
|
{
|
2020-04-03 13:25:03 +02:00
|
|
|
ScrArea *area = CTX_wm_area(C);
|
|
|
|
ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_UI);
|
2020-02-28 14:33:31 +01:00
|
|
|
SpaceFile *sf = CTX_wm_space_file(C);
|
|
|
|
|
2020-06-10 01:07:49 +10:00
|
|
|
ARegion *region_ctx = CTX_wm_region(C);
|
|
|
|
CTX_wm_region_set(C, region);
|
2020-03-06 16:56:42 +01:00
|
|
|
UI_textbutton_activate_rna(C, region, sf->params, "filter_search");
|
2020-06-10 01:07:49 +10:00
|
|
|
CTX_wm_region_set(C, region_ctx);
|
|
|
|
|
2020-02-28 14:33:31 +01:00
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FILE_OT_start_filter(struct wmOperatorType *ot)
|
|
|
|
{
|
|
|
|
/* identifiers */
|
|
|
|
ot->name = "Filter";
|
|
|
|
ot->description = "Start entering filter text";
|
|
|
|
ot->idname = "FILE_OT_start_filter";
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
ot->exec = file_start_filter_exec;
|
|
|
|
ot->poll = ED_operator_file_active;
|
|
|
|
}
|
|
|
|
|
2020-03-25 21:24:59 +11:00
|
|
|
/** \} */
|
|
|
|
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
/** \name Macro Operators
|
|
|
|
* \{ */
|
|
|
|
|
2010-01-19 03:59:05 +00:00
|
|
|
void ED_operatormacros_file(void)
|
|
|
|
{
|
2019-04-17 06:17:24 +02:00
|
|
|
// wmOperatorType *ot;
|
|
|
|
// wmOperatorTypeMacro *otmacro;
|
2018-06-04 09:31:30 +02:00
|
|
|
|
2019-04-17 06:17:24 +02:00
|
|
|
/* future macros */
|
2010-01-19 03:59:05 +00:00
|
|
|
}
|
2020-03-25 21:24:59 +11:00
|
|
|
|
|
|
|
/** \} */
|