diff options
author | Jacques Lucke <mail@jlucke.com> | 2019-09-03 17:30:22 +0300 |
---|---|---|
committer | Jacques Lucke <mail@jlucke.com> | 2019-09-03 17:30:22 +0300 |
commit | 4dd3773283fe4d0f01c51b25e982fc5afc9a2265 (patch) | |
tree | 364d28328ec24b280a2ab4ff5081a9cab8788e80 /source/blender | |
parent | 8443f319e335cb36ce671dba80218a14f817af1b (diff) | |
parent | ee8f69c96cba62b083fb089432cddd0bce5d08e1 (diff) |
Merge branch 'master' into functions
Diffstat (limited to 'source/blender')
48 files changed, 1275 insertions, 707 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index db93193bfe3..65086f57616 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -37,6 +37,8 @@ #define BLENDER_VERSION_CHAR /** alpha/beta/rc/release, docs use this. */ #define BLENDER_VERSION_CYCLE alpha +/** Optionally set to 1,2,... for example to to get alpha1 or rc2. */ +#define BLENDER_VERSION_CYCLE_NUMBER /** Defined in from blender.c */ extern char versionstr[]; diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 6bd7440eeea..105f8e82343 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -96,7 +96,7 @@ typedef struct bContextStore { /* for the context's rna mode enum * keep aligned with data_mode_strings in context.c */ -enum eContextObjectMode { +typedef enum eContextObjectMode { CTX_MODE_EDIT_MESH = 0, CTX_MODE_EDIT_CURVE, CTX_MODE_EDIT_SURFACE, @@ -115,7 +115,7 @@ enum eContextObjectMode { CTX_MODE_EDIT_GPENCIL, CTX_MODE_SCULPT_GPENCIL, CTX_MODE_WEIGHT_GPENCIL, -}; +} eContextObjectMode; #define CTX_MODE_NUM (CTX_MODE_WEIGHT_GPENCIL + 1) /* Context */ diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 7ea395e9386..ed517bfc513 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -2985,6 +2985,15 @@ bool BKE_object_empty_image_data_is_visible_in_view3d(const Object *ob, const Re } } + if (visibility_flag & OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED) { + float proj[3]; + project_plane_v3_v3v3(proj, ob->obmat[2], rv3d->viewinv[2]); + const float proj_length_sq = len_squared_v3(proj); + if (proj_length_sq > 1e-5f) { + return false; + } + } + return true; } diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index d8daa81b58d..d78f167a8fd 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -99,8 +99,13 @@ void BLI_filelist_entry_size_to_string(const struct stat *st, void BLI_filelist_entry_mode_to_string( const struct stat *st, const bool compact, char r_mode1[], char r_mode2[], char r_mode3[]); void BLI_filelist_entry_owner_to_string(const struct stat *st, const bool compact, char r_owner[]); -void BLI_filelist_entry_datetime_to_string( - const struct stat *st, const int64_t ts, const bool compact, char r_time[], char r_date[]); +void BLI_filelist_entry_datetime_to_string(const struct stat *st, + const int64_t ts, + const bool compact, + char r_time[], + char r_date[], + bool *r_is_today, + bool *r_is_yesterday); /* Files */ diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index a93632cca08..c92505acb54 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -261,36 +261,17 @@ unsigned int BLI_filelist_dir_contents(const char *dirname, struct direntry **r_ */ void BLI_filelist_entry_size_to_string(const struct stat *st, const uint64_t sz, - const bool compact, + /* Used to change MB -> M, etc. - is that really useful? */ + const bool UNUSED(compact), char r_size[FILELIST_DIRENTRY_SIZE_LEN]) { - double size; - const char *fmt; - const char *units[] = {"KiB", "MiB", "GiB", "TiB", NULL}; - const char *units_compact[] = {"K", "M", "G", "T", NULL}; - const char *unit = "B"; - /* * Seems st_size is signed 32-bit value in *nix and Windows. This * will buy us some time until files get bigger than 4GB or until * everyone starts using __USE_FILE_OFFSET64 or equivalent. */ - size = (double)(st ? st->st_size : sz); - - if (size > 1024.0) { - const char **u; - for (u = compact ? units_compact : units, size /= 1024.0; size > 1024.0 && *(u + 1); - u++, size /= 1024.0) { - /* pass */ - } - fmt = size > 100.0 ? "%.0f %s" : (size > 10.0 ? "%.1f %s" : "%.2f %s"); - unit = *u; - } - else { - fmt = "%.0f %s"; - } - - BLI_snprintf(r_size, sizeof(*r_size) * FILELIST_DIRENTRY_SIZE_LEN, fmt, size, unit); + double size = (double)(st ? st->st_size : sz); + BLI_str_format_byte_unit(r_size, size, true); } /** @@ -366,14 +347,45 @@ void BLI_filelist_entry_owner_to_string(const struct stat *st, /** * Convert given entry's time into human-readable strings. + * + * \param r_is_today: optional, returns true if the date matches today's. + * \param r_is_yesterday: optional, returns true if the date matches yesterday's. */ void BLI_filelist_entry_datetime_to_string(const struct stat *st, const int64_t ts, const bool compact, char r_time[FILELIST_DIRENTRY_TIME_LEN], - char r_date[FILELIST_DIRENTRY_DATE_LEN]) + char r_date[FILELIST_DIRENTRY_DATE_LEN], + bool *r_is_today, + bool *r_is_yesterday) { - time_t ts_mtime = ts; + int today_year = 0; + int today_yday = 0; + int yesterday_year = 0; + int yesterday_yday = 0; + + if (r_is_today || r_is_yesterday) { + /* Localtime() has only one buffer so need to get data out before called again. */ + const time_t ts_now = time(NULL); + struct tm *today = localtime(&ts_now); + + today_year = today->tm_year; + today_yday = today->tm_yday; + /* Handle a yesterday that spans a year */ + today->tm_mday--; + mktime(today); + yesterday_year = today->tm_year; + yesterday_yday = today->tm_yday; + + if (r_is_today) { + *r_is_today = false; + } + if (r_is_yesterday) { + *r_is_yesterday = false; + } + } + + const time_t ts_mtime = ts; const struct tm *tm = localtime(st ? &st->st_mtime : &ts_mtime); const time_t zero = 0; @@ -385,12 +397,20 @@ void BLI_filelist_entry_datetime_to_string(const struct stat *st, if (r_time) { strftime(r_time, sizeof(*r_time) * FILELIST_DIRENTRY_TIME_LEN, "%H:%M", tm); } + if (r_date) { strftime(r_date, sizeof(*r_date) * FILELIST_DIRENTRY_DATE_LEN, - compact ? "%d/%m/%y" : "%d-%b-%y", + compact ? "%d/%m/%y" : "%d %b %Y", tm); } + + if (r_is_today && (tm->tm_year == today_year) && (tm->tm_yday == today_yday)) { + *r_is_today = true; + } + else if (r_is_yesterday && (tm->tm_year == yesterday_year) && (tm->tm_yday == yesterday_yday)) { + *r_is_yesterday = true; + } } /** diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index ae98d3e0e15..a9f369908e7 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3722,5 +3722,39 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) { /* Versioning code until next subversion bump goes here. */ + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) { + for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) { + if (sl->spacetype == SPACE_FILE) { + SpaceFile *sfile = (SpaceFile *)sl; + ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase; + ARegion *ar_ui = do_versions_find_region(regionbase, RGN_TYPE_UI); + ARegion *ar_header = do_versions_find_region(regionbase, RGN_TYPE_HEADER); + ARegion *ar_toolprops = do_versions_find_region_or_null(regionbase, + RGN_TYPE_TOOL_PROPS); + + /* Reinsert UI region so that it spawns entire area width */ + BLI_remlink(regionbase, ar_ui); + BLI_insertlinkafter(regionbase, ar_header, ar_ui); + + ar_ui->flag |= RGN_FLAG_DYNAMIC_SIZE; + + if (ar_toolprops && (ar_toolprops->alignment == (RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV))) { + SpaceType *stype = BKE_spacetype_from_id(sl->spacetype); + + /* Remove empty region at old location. */ + BLI_assert(sfile->op == NULL); + BKE_area_region_free(stype, ar_toolprops); + BLI_freelinkN(regionbase, ar_toolprops); + } + + if (sfile->params) { + sfile->params->details_flags |= FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; + } + } + } + } + } } } diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 8bbfc29131e..67b8ce1d0de 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -150,6 +150,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) * Include next version bump. */ { + FROM_DEFAULT_V4_UCHAR(space_file.execution_buts); } #undef FROM_DEFAULT_V4_UCHAR diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h index fd12f90016b..7553eca9b64 100644 --- a/source/blender/depsgraph/DEG_depsgraph.h +++ b/source/blender/depsgraph/DEG_depsgraph.h @@ -108,6 +108,8 @@ void DEG_graph_on_visible_update(struct Main *bmain, Depsgraph *depsgraph, const /* Update all dependency graphs when visible scenes/layers changes. */ void DEG_on_visible_update(struct Main *bmain, const bool do_time); +/* NOTE: Will return NULL if the flag is not known, allowing to gracefully handle situations + * when recalc flag has been removed. */ const char *DEG_update_tag_as_string(IDRecalcFlag flag); void DEG_id_tag_update(struct ID *id, int flag); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index c36ef0f7d1b..5fcbd80ea4d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -809,13 +809,25 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) { Object *parent = object->parent; ID *parent_id = &object->parent->id; - ComponentKey ob_key(&object->id, NodeType::TRANSFORM); - /* Type-specific links/ */ + ComponentKey object_transform_key(&object->id, NodeType::TRANSFORM); + /* Type-specific links. */ switch (object->partype) { /* Armature Deform (Virtual Modifier) */ case PARSKEL: { - ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Armature Deform Parent"); + ComponentKey parent_transform_key(parent_id, NodeType::TRANSFORM); + add_relation(parent_transform_key, object_transform_key, "Parent Armature Transform"); + + if (parent->type == OB_ARMATURE) { + ComponentKey object_geometry_key(&object->id, NodeType::GEOMETRY); + ComponentKey parent_pose_key(parent_id, NodeType::EVAL_POSE); + add_relation( + parent_transform_key, object_geometry_key, "Parent Armature Transform -> Geometry"); + add_relation(parent_pose_key, object_geometry_key, "Parent Armature Pose -> Geometry"); + + add_depends_on_transform_relation( + &object->id, object_geometry_key, "Virtual Armature Modifier"); + } + break; } @@ -823,7 +835,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) case PARVERT1: case PARVERT3: { ComponentKey parent_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Vertex Parent"); + add_relation(parent_key, object_transform_key, "Vertex Parent"); /* Original index is used for optimizations of lookups for subdiv * only meshes. * TODO(sergey): This optimization got lost at 2.8, so either verify @@ -835,7 +847,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) DEGCustomDataMeshMasks::MaskFace(CD_MASK_ORIGINDEX) | DEGCustomDataMeshMasks::MaskPoly(CD_MASK_ORIGINDEX)); ComponentKey transform_key(parent_id, NodeType::TRANSFORM); - add_relation(transform_key, ob_key, "Vertex Parent TFM"); + add_relation(transform_key, object_transform_key, "Vertex Parent TFM"); break; } @@ -844,8 +856,8 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) ComponentKey parent_bone_key(parent_id, NodeType::BONE, object->parsubstr); OperationKey parent_transform_key( parent_id, NodeType::TRANSFORM, OperationCode::TRANSFORM_FINAL); - add_relation(parent_bone_key, ob_key, "Bone Parent"); - add_relation(parent_transform_key, ob_key, "Armature Parent"); + add_relation(parent_bone_key, object_transform_key, "Bone Parent"); + add_relation(parent_transform_key, object_transform_key, "Armature Parent"); break; } @@ -854,8 +866,8 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) /* Lattice Deform Parent - Virtual Modifier. */ ComponentKey parent_key(parent_id, NodeType::TRANSFORM); ComponentKey geom_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Lattice Deform Parent"); - add_relation(geom_key, ob_key, "Lattice Deform Parent Geom"); + add_relation(parent_key, object_transform_key, "Lattice Deform Parent"); + add_relation(geom_key, object_transform_key, "Lattice Deform Parent Geom"); } else if (object->parent->type == OB_CURVE) { Curve *cu = (Curve *)object->parent->data; @@ -863,20 +875,20 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) if (cu->flag & CU_PATH) { /* Follow Path. */ ComponentKey parent_key(parent_id, NodeType::GEOMETRY); - add_relation(parent_key, ob_key, "Curve Follow Parent"); + add_relation(parent_key, object_transform_key, "Curve Follow Parent"); ComponentKey transform_key(parent_id, NodeType::TRANSFORM); - add_relation(transform_key, ob_key, "Curve Follow TFM"); + add_relation(transform_key, object_transform_key, "Curve Follow TFM"); } else { /* Standard Parent. */ ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Curve Parent"); + add_relation(parent_key, object_transform_key, "Curve Parent"); } } else { /* Standard Parent. */ ComponentKey parent_key(parent_id, NodeType::TRANSFORM); - add_relation(parent_key, ob_key, "Parent"); + add_relation(parent_key, object_transform_key, "Parent"); } break; } @@ -889,7 +901,7 @@ void DepsgraphRelationBuilder::build_object_parent(Object *object) ComponentKey parent_geometry_key(parent_id, NodeType::GEOMETRY); /* NOTE: Metaballs are evaluating geometry only after their transform, * so we only hook up to transform channel here. */ - add_relation(parent_geometry_key, ob_key, "Parent"); + add_relation(parent_geometry_key, object_transform_key, "Parent"); } /* Dupliverts uses original vertex index. */ diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index b73a3c08e10..72ef495f1d5 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -412,11 +412,15 @@ static void graph_id_tag_update_single_flag(Main *bmain, string stringify_append_bit(const string &str, IDRecalcFlag tag) { + const char *tag_name = DEG_update_tag_as_string(tag); + if (tag_name == NULL) { + return str; + } string result = str; if (!result.empty()) { result += ", "; } - result += DEG_update_tag_as_string(tag); + result += tag_name; return result; } @@ -717,8 +721,7 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) case ID_RECALC_ALL: return "ALL"; } - BLI_assert(!"Unhandled update flag, should never happen!"); - return "UNKNOWN"; + return NULL; } /* Data-Based Tagging */ diff --git a/source/blender/draw/engines/select/select_draw_utils.c b/source/blender/draw/engines/select/select_draw_utils.c index ec47d6ea8eb..6a51c28c242 100644 --- a/source/blender/draw/engines/select/select_draw_utils.c +++ b/source/blender/draw/engines/select/select_draw_utils.c @@ -62,13 +62,19 @@ void select_id_object_min_max(Object *obj, float r_min[3], float r_max[3]) short select_id_get_object_select_mode(Scene *scene, Object *ob) { short r_select_mode = 0; - if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)) { + if (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT)) { Mesh *me_orig = DEG_get_original_object(ob)->data; if (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) { r_select_mode = SCE_SELECT_FACE; } - if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) { - r_select_mode |= SCE_SELECT_VERTEX; + else if (me_orig->editflag & ME_EDIT_PAINT_VERT_SEL) { + r_select_mode = SCE_SELECT_VERTEX; + } + } + else if (ob->mode & OB_MODE_TEXTURE_PAINT) { + Mesh *me_orig = DEG_get_original_object(ob)->data; + if (me_orig->editflag & ME_EDIT_PAINT_FACE_SEL) { + r_select_mode = SCE_SELECT_FACE; } } else { diff --git a/source/blender/draw/engines/select/select_engine.c b/source/blender/draw/engines/select/select_engine.c index 5dc20a589f0..c294bba2083 100644 --- a/source/blender/draw/engines/select/select_engine.c +++ b/source/blender/draw/engines/select/select_engine.c @@ -163,6 +163,13 @@ static void select_cache_init(void *vedata) if (e_data.context.select_mode == -1) { e_data.context.select_mode = select_id_get_object_select_mode(draw_ctx->scene, draw_ctx->obact); + if (e_data.context.select_mode == 0) { + /* Need for sampling weights. */ + if (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) { + e_data.context.select_mode = SCE_SELECT_FACE; + } + } + BLI_assert(e_data.context.select_mode != 0); } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 3d8a7bb1e30..b64b6f9a788 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -33,6 +33,7 @@ #include "BKE_anim.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_curve.h" #include "BKE_editmesh.h" #include "BKE_global.h" @@ -41,6 +42,7 @@ #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_mesh.h" +#include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_particle.h" #include "BKE_paint.h" @@ -2204,24 +2206,43 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, drw_state_prepare_clean_for_draw(&DST); bool use_obedit = false; - int obedit_mode = 0; + /* obedit_ctx_mode is used for selecting the right draw engines */ + eContextObjectMode obedit_ctx_mode; + /* object_mode is used for filtering objects in the depsgraph */ + eObjectMode object_mode; + int object_type = 0; if (obedit != NULL) { + object_type = obedit->type; + object_mode = obedit->mode; if (obedit->type == OB_MBALL) { use_obedit = true; - obedit_mode = CTX_MODE_EDIT_METABALL; + obedit_ctx_mode = CTX_MODE_EDIT_METABALL; } else if (obedit->type == OB_ARMATURE) { use_obedit = true; - obedit_mode = CTX_MODE_EDIT_ARMATURE; + obedit_ctx_mode = CTX_MODE_EDIT_ARMATURE; } } if (v3d->overlay.flag & V3D_OVERLAY_BONE_SELECT) { if (!(v3d->flag2 & V3D_HIDE_OVERLAYS)) { /* Note: don't use "BKE_object_pose_armature_get" here, it breaks selection. */ Object *obpose = OBPOSE_FROM_OBACT(obact); + if (obpose == NULL) { + Object *obweight = OBWEIGHTPAINT_FROM_OBACT(obact); + if (obweight) { + /* Only use Armature pose selection, when connected armature is in pose mode. */ + Object *ob_armature = modifiers_isDeformedByArmature(obweight); + if (ob_armature && ob_armature->mode == OB_MODE_POSE) { + obpose = ob_armature; + } + } + } + if (obpose) { use_obedit = true; - obedit_mode = CTX_MODE_POSE; + object_type = obpose->type; + object_mode = obpose->mode; + obedit_ctx_mode = CTX_MODE_POSE; } } } @@ -2235,8 +2256,8 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, /* Get list of enabled engines */ if (use_obedit) { - drw_engines_enable_from_paint_mode(obedit_mode); - drw_engines_enable_from_mode(obedit_mode); + drw_engines_enable_from_paint_mode(obedit_ctx_mode); + drw_engines_enable_from_mode(obedit_ctx_mode); } else if (!draw_surface) { /* grease pencil selection */ @@ -2283,7 +2304,7 @@ void DRW_draw_select_loop(struct Depsgraph *depsgraph, drw_engines_world_update(scene); if (use_obedit) { - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, obact->type, obact->mode, ob_iter) { + FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, v3d, object_type, object_mode, ob_iter) { drw_engines_cache_populate(ob_iter); } FOREACH_OBJECT_IN_MODE_END; diff --git a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl index 7dfbf469adc..e33aa6cdcc1 100644 --- a/source/blender/draw/modes/shaders/object_empty_image_frag.glsl +++ b/source/blender/draw/modes/shaders/object_empty_image_frag.glsl @@ -37,9 +37,15 @@ void main() if (depthMode == DEPTH_BACK) { gl_FragDepth = 0.999999; +#ifdef USE_WIRE + gl_FragDepth -= 1e-5; +#endif } else if (depthMode == DEPTH_FRONT) { gl_FragDepth = 0.000001; +#ifdef USE_WIRE + gl_FragDepth -= 1e-5; +#endif } else if (depthMode == DEPTH_UNCHANGED) { gl_FragDepth = gl_FragCoord.z; diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 7273f857a41..dc42237d804 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -34,17 +34,32 @@ struct wmWindowManager; #define FILE_LAYOUT_HOR 1 #define FILE_LAYOUT_VER 2 -#define MAX_FILE_COLUMN 4 - -typedef enum FileListColumns { +typedef enum FileAttributeColumnType { + COLUMN_NONE = -1, COLUMN_NAME = 0, - COLUMN_DATE, - COLUMN_TIME, + COLUMN_DATETIME, COLUMN_SIZE, -} FileListColumns; + + ATTRIBUTE_COLUMN_MAX +} FileAttributeColumnType; + +typedef struct FileAttributeColumn { + /** UI name for this column */ + const char *name; + + float width; + /* The sort type to use when sorting by this column. */ + int sort_type; /* eFileSortType */ + + /* Alignment of column texts, header text is always left aligned */ + int text_align; /* eFontStyle_Align */ +} FileAttributeColumn; typedef struct FileLayout { /* view settings - XXX - move into own struct */ + int offset_top; + /* Height of the header for the different FileAttributeColumn's. */ + int attribute_column_header_h; int prv_w; int prv_h; int tile_w; @@ -54,13 +69,17 @@ typedef struct FileLayout { int prv_border_x; int prv_border_y; int rows; - int columns; + /* Those are the major layout columns the files are distributed across, not to be confused with + * 'attribute_columns' array below. */ + int flow_columns; int width; int height; int flag; int dirty; int textheight; - float column_widths[MAX_FILE_COLUMN]; + /* The columns for each item (name, modification date/time, size). Not to be confused with the + * 'flow_columns' above. */ + FileAttributeColumn attribute_columns[ATTRIBUTE_COLUMN_MAX]; /* When we change display size, we may have to update static strings like size of files... */ short curr_size; @@ -72,6 +91,7 @@ typedef struct FileSelection { } FileSelection; struct rcti; +struct View2D; struct FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile); @@ -87,6 +107,17 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, struct ARegion *ar); int ED_fileselect_layout_offset(FileLayout *layout, int x, int y); FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const struct rcti *rect); +void ED_fileselect_layout_maskrect(const FileLayout *layout, + const struct View2D *v2d, + struct rcti *r_rect); +bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, + const struct View2D *v2d, + int x, + int y); +bool ED_fileselect_layout_isect_rect(const FileLayout *layout, + const struct View2D *v2d, + const struct rcti *rect, + struct rcti *r_dst); void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y); void ED_operatormacros_file(void); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 524474cce88..7ada4755a64 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -2244,6 +2244,8 @@ int UI_idcode_icon_get(const int idcode) return ICON_FONT_DATA; case ID_WO: return ICON_WORLD_DATA; + case ID_WS: + return ICON_WORKSPACE; default: return ICON_NONE; } diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index a0f493d0011..b0c9e3b9378 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1265,9 +1265,6 @@ static void region_rect_recursive( else if (ED_area_is_global(sa)) { prefsizey = ED_region_global_size_y(); } - else if (ar->regiontype == RGN_TYPE_UI && sa->spacetype == SPACE_FILE) { - prefsizey = UI_UNIT_Y * 2 + (UI_UNIT_Y / 2); - } else { prefsizey = UI_DPI_FAC * (ar->sizey > 1 ? ar->sizey + 0.5f : ar->type->prefsizey); } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 0ab21990086..50e5597ac0c 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3936,6 +3936,65 @@ static void SCREEN_OT_region_quadview(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Region Toggle Operator + * \{ */ + +static int region_toggle_exec(bContext *C, wmOperator *op) +{ + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "region_type"); + ARegion *region; + + if (RNA_property_is_set(op->ptr, prop)) { + region = BKE_area_find_region_type(CTX_wm_area(C), RNA_property_enum_get(op->ptr, prop)); + } + else { + region = CTX_wm_region(C); + } + + if (region) { + ED_region_toggle_hidden(C, region); + } + ED_region_tag_redraw(region); + + return OPERATOR_FINISHED; +} + +static bool region_toggle_poll(bContext *C) +{ + ScrArea *area = CTX_wm_area(C); + + /* don't flip anything around in topbar */ + if (area && area->spacetype == SPACE_TOPBAR) { + CTX_wm_operator_poll_msg_set(C, "Toggling regions in the Top-bar is not allowed"); + return 0; + } + + return ED_operator_areaactive(C); +} + +static void SCREEN_OT_region_toggle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Toggle Region"; + ot->idname = "SCREEN_OT_region_toggle"; + ot->description = "Hide or unhide the region"; + + /* api callbacks */ + ot->exec = region_toggle_exec; + ot->poll = region_toggle_poll; + ot->flag = 0; + + RNA_def_enum(ot->srna, + "region_type", + rna_enum_region_type_items, + 0, + "Region Type", + "Type of the region to toggle"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Region Flip Operator * \{ */ @@ -5361,6 +5420,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(SCREEN_OT_area_swap); WM_operatortype_append(SCREEN_OT_region_quadview); WM_operatortype_append(SCREEN_OT_region_scale); + WM_operatortype_append(SCREEN_OT_region_toggle); WM_operatortype_append(SCREEN_OT_region_flip); WM_operatortype_append(SCREEN_OT_header_toggle_menus); WM_operatortype_append(SCREEN_OT_region_context_menu); diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index 51231ccf634..4e710d31cbb 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -710,7 +710,7 @@ static void SOUND_OT_mixdown(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_SOUND, FILE_SPECIAL, FILE_SAVE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); #ifdef WITH_AUDASPACE diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 3a6d59c1dbf..0083fc244d8 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -26,6 +26,7 @@ #include <errno.h> #include "BLI_blenlib.h" +#include "BLI_fileops_types.h" #include "BLI_utildefines.h" #include "BLI_math.h" @@ -77,234 +78,6 @@ static char *file_draw_tooltip_func(bContext *UNUSED(C), void *argN, const char return BLI_strdup(dyn_tooltip); } -/* Note: This function uses pixelspace (0, 0, winx, winy), not view2d. - * The controls are laid out as follows: - * - * ------------------------------------------- - * | Directory input | execute | - * ------------------------------------------- - * | Filename input | + | - | cancel | - * ------------------------------------------- - * - * The input widgets will stretch to fill any excess space. - * When there isn't enough space for all controls to be shown, they are - * hidden in this order: x/-, execute/cancel, input widgets. - */ -void file_draw_buttons(const bContext *C, ARegion *ar) -{ - /* Button layout. */ - const int max_x = ar->winx - 10; - const int line1_y = ar->winy - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); - const int line2_y = line1_y - (IMASEL_BUTTONS_HEIGHT / 2 + IMASEL_BUTTONS_MARGIN); - const int input_minw = 20; - const int btn_h = UI_UNIT_Y; - const int btn_fn_w = UI_UNIT_X; - const int btn_minw = 80; - const int btn_margin = 20; - const int separator = 4; - - /* Additional locals. */ - char uiblockstr[32]; - int loadbutton; - int fnumbuttons; - int min_x = 10; - int chan_offs = 0; - int available_w = max_x - min_x; - int line1_w = available_w; - int line2_w = available_w; - - uiBut *but; - uiBlock *block; - SpaceFile *sfile = CTX_wm_space_file(C); - FileSelectParams *params = ED_fileselect_get_params(sfile); - ARegion *artmp; - const bool is_browse_only = (sfile->op == NULL); - - /* Initialize UI block. */ - BLI_snprintf(uiblockstr, sizeof(uiblockstr), "win %p", (void *)ar); - block = UI_block_begin(C, ar, uiblockstr, UI_EMBOSS); - - /* exception to make space for collapsed region icon */ - for (artmp = CTX_wm_area(C)->regionbase.first; artmp; artmp = artmp->next) { - if (artmp->regiontype == RGN_TYPE_TOOLS && artmp->flag & RGN_FLAG_HIDDEN) { - chan_offs = 16; - min_x += chan_offs; - available_w -= chan_offs; - } - } - - /* Is there enough space for the execute / cancel buttons? */ - - if (is_browse_only) { - loadbutton = 0; - } - else { - const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; - loadbutton = UI_fontstyle_string_width(fstyle, params->title) + btn_margin; - CLAMP_MIN(loadbutton, btn_minw); - if (available_w <= loadbutton + separator + input_minw) { - loadbutton = 0; - } - } - - if (loadbutton) { - line1_w -= (loadbutton + separator); - line2_w = line1_w; - } - - /* Is there enough space for file number increment/decrement buttons? */ - fnumbuttons = 2 * btn_fn_w; - if (!loadbutton || line2_w <= fnumbuttons + separator + input_minw) { - fnumbuttons = 0; - } - else { - line2_w -= (fnumbuttons + separator); - } - - /* Text input fields for directory and file. */ - if (available_w > 0) { - const struct FileDirEntry *file = sfile->files ? - filelist_file(sfile->files, params->active_file) : - NULL; - int overwrite_alert = file_draw_check_exists(sfile); - const bool is_active_dir = file && (file->typeflag & FILE_TYPE_FOLDER); - - /* callbacks for operator check functions */ - UI_block_func_set(block, file_draw_check_cb, NULL, NULL); - - but = uiDefBut(block, - UI_BTYPE_TEXT, - -1, - "", - min_x, - line1_y, - line1_w - chan_offs, - btn_h, - params->dir, - 0.0, - (float)FILE_MAX, - 0, - 0, - TIP_("File path")); - UI_but_func_complete_set(but, autocomplete_directory, NULL); - UI_but_flag_enable(but, UI_BUT_NO_UTF8); - UI_but_flag_disable(but, UI_BUT_UNDO); - UI_but_funcN_set(but, file_directory_enter_handle, NULL, but); - - /* TODO, directory editing is non-functional while a library is loaded - * until this is properly supported just disable it. */ - if (sfile->files && filelist_lib(sfile->files)) { - UI_but_flag_enable(but, UI_BUT_DISABLED); - } - - if ((params->flag & FILE_DIRSEL_ONLY) == 0) { - but = uiDefBut( - block, - UI_BTYPE_TEXT, - -1, - "", - min_x, - line2_y, - line2_w - chan_offs, - btn_h, - is_active_dir ? (char *)"" : params->file, - 0.0, - (float)FILE_MAXFILE, - 0, - 0, - TIP_(overwrite_alert ? N_("File name, overwrite existing") : N_("File name"))); - UI_but_func_complete_set(but, autocomplete_file, NULL); - UI_but_flag_enable(but, UI_BUT_NO_UTF8); - UI_but_flag_disable(but, UI_BUT_UNDO); - /* silly workaround calling NFunc to ensure this does not get called - * immediate ui_apply_but_func but only after button deactivates */ - UI_but_funcN_set(but, file_filename_enter_handle, NULL, but); - - /* check if this overrides a file and if the operator option is used */ - if (overwrite_alert) { - UI_but_flag_enable(but, UI_BUT_REDALERT); - } - } - - /* clear func */ - UI_block_func_set(block, NULL, NULL, NULL); - } - - /* Filename number increment / decrement buttons. */ - if (fnumbuttons && (params->flag & FILE_DIRSEL_ONLY) == 0) { - UI_block_align_begin(block); - but = uiDefIconButO(block, - UI_BTYPE_BUT, - "FILE_OT_filenum", - 0, - ICON_REMOVE, - min_x + line2_w + separator - chan_offs, - line2_y, - btn_fn_w, - btn_h, - TIP_("Decrement the filename number")); - RNA_int_set(UI_but_operator_ptr_get(but), "increment", -1); - - but = uiDefIconButO(block, - UI_BTYPE_BUT, - "FILE_OT_filenum", - 0, - ICON_ADD, - min_x + line2_w + separator + btn_fn_w - chan_offs, - line2_y, - btn_fn_w, - btn_h, - TIP_("Increment the filename number")); - RNA_int_set(UI_but_operator_ptr_get(but), "increment", 1); - UI_block_align_end(block); - } - - /* Execute / cancel buttons. */ - if (loadbutton) { - const struct FileDirEntry *file = sfile->files ? - filelist_file(sfile->files, params->active_file) : - NULL; - char const *str_exec; - - if (file && FILENAME_IS_PARENT(file->relpath)) { - str_exec = IFACE_("Parent Directory"); - } - else if (file && file->typeflag & FILE_TYPE_DIR) { - str_exec = IFACE_("Open Directory"); - } - else { - str_exec = params->title; /* params->title is already translated! */ - } - - but = uiDefButO(block, - UI_BTYPE_BUT, - "FILE_OT_execute", - WM_OP_EXEC_REGION_WIN, - str_exec, - max_x - loadbutton, - line1_y, - loadbutton, - btn_h, - ""); - /* Just a display hint. */ - UI_but_flag_enable(but, UI_BUT_ACTIVE_DEFAULT); - - uiDefButO(block, - UI_BTYPE_BUT, - "FILE_OT_cancel", - WM_OP_EXEC_REGION_WIN, - IFACE_("Cancel"), - max_x - loadbutton, - line2_y, - loadbutton, - btn_h, - ""); - } - - UI_block_end(C, block); - UI_block_draw(C, block); -} - static void draw_tile(int sx, int sy, int width, int height, int colorid, int shade) { float color[4]; @@ -349,7 +122,7 @@ static void file_draw_string(int sx, rcti rect; char fname[FILE_MAXFILE]; - if (string[0] == '\0') { + if (string[0] == '\0' || width < 1) { return; } @@ -362,7 +135,7 @@ static void file_draw_string(int sx, /* no text clipping needed, UI_fontstyle_draw does it but is a bit too strict * (for buttons it works) */ rect.xmin = sx; - rect.xmax = (int)(sx + ceil(width + 5.0f / UI_DPI_FAC)); + rect.xmax = sx + round_fl_to_int(width); rect.ymin = sy - height; rect.ymax = sy; @@ -404,8 +177,8 @@ static void file_draw_preview(uiBlock *block, float scaledx, scaledy; float scale; int ex, ey; - bool use_dropshadow = !is_icon && (typeflags & FILE_TYPE_IMAGE); - float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + bool use_dropshadow = !is_icon && + (typeflags & (FILE_TYPE_IMAGE | FILE_TYPE_MOVIE | FILE_TYPE_BLENDER)); BLI_assert(imb != NULL); @@ -442,13 +215,27 @@ static void file_draw_preview(uiBlock *block, /* shadow */ if (use_dropshadow) { - UI_draw_box_shadow(220, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + UI_draw_box_shadow(128, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); } GPU_blend(true); - /* the image */ - if (!is_icon && typeflags & FILE_TYPE_FTFONT) { + /* the large image */ + + float col[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + if (is_icon) { + /* File and Folder icons draw with lowered opacity until we add themes */ + col[3] = 0.6f; + /* Use dark images if background is light */ + float bg[3]; + UI_GetThemeColor3fv(TH_BACK, bg); + if (rgb_to_grayscale(bg) > 0.5f) { + col[0] = 0; + col[1] = 0; + col[2] = 0; + } + } + else if (typeflags & FILE_TYPE_FTFONT) { UI_GetThemeColor4fv(TH_TEXT, col); } @@ -477,30 +264,61 @@ static void file_draw_preview(uiBlock *block, GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - if (icon) { - UI_icon_draw_ex((float)xco + (7 * UI_DPI_FAC), - (float)yco + (7 * UI_DPI_FAC), - icon, - icon_aspect, - 1.0f, - 0.0f, - NULL, - false); + if (icon && (icon != ICON_FILE_FONT)) { + /* size of center icon is scaled to fit container and UI scale */ + float icon_x, icon_y; + + if (is_icon) { + const float icon_size = 16.0f / icon_aspect * U.dpi_fac; + float icon_opacity = MIN2(icon_aspect, 0.7); + uchar icon_color[4] = {255, 255, 255, 255}; + float bg[3]; + /* base this off theme color of file or folder later */ + UI_GetThemeColor3fv(TH_BACK, bg); + if (rgb_to_grayscale(bg) > 0.5f) { + icon_color[0] = 0; + icon_color[1] = 0; + icon_color[2] = 0; + } + icon_x = xco + (ex / 2.0f) - (icon_size / 2.0f); + icon_y = yco + (ey / 2.0f) - (icon_size * ((typeflags & FILE_TYPE_DIR) ? 0.78f : 0.65f)); + UI_icon_draw_ex( + icon_x, icon_y, icon, icon_aspect / U.dpi_fac, icon_opacity, 0.0f, icon_color, false); + } + else { + const uchar dark[4] = {0, 0, 0, 255}; + const uchar light[4] = {255, 255, 255, 255}; + + /* Smaller, fainter icon for preview image thumbnail. */ + icon_x = xco + (2.0f * UI_DPI_FAC); + icon_y = yco + (2.0f * UI_DPI_FAC); + + UI_icon_draw_ex(icon_x + 1, icon_y - 1, icon, 1.0f / U.dpi_fac, 0.2f, 0.0f, dark, false); + UI_icon_draw_ex(icon_x, icon_y, icon, 1.0f / U.dpi_fac, 0.6f, 0.0f, light, false); + } } /* border */ if (use_dropshadow) { GPUVertFormat *format = immVertexFormat(); - uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint pos_attr = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint col_attr = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - immUniformColor4f(0.0f, 0.0f, 0.0f, 0.4f); - imm_draw_box_wire_2d(pos, (float)xco, (float)yco, (float)(xco + ex), (float)(yco + ey)); + immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + immBegin(GPU_PRIM_LINE_LOOP, 4); + immAttr4f(col_attr, 1.0f, 1.0f, 1.0f, 0.15f); + immVertex2f(pos_attr, (float)xco + 1, (float)(yco + ey)); + immAttr4f(col_attr, 1.0f, 1.0f, 1.0f, 0.2f); + immVertex2f(pos_attr, (float)(xco + ex), (float)(yco + ey)); + immAttr4f(col_attr, 0.0f, 0.0f, 0.0f, 0.2f); + immVertex2f(pos_attr, (float)(xco + ex), (float)yco + 1); + immAttr4f(col_attr, 0.0f, 0.0f, 0.0f, 0.3f); + immVertex2f(pos_attr, (float)xco + 1, (float)yco + 1); + immEnd(); immUnbindProgram(); } but = uiDefBut(block, UI_BTYPE_LABEL, 0, "", xco, yco, ex, ey, NULL, 0.0, 0.0, 0, 0, NULL); - UI_but_func_tooltip_set(but, file_draw_tooltip_func, BLI_strdup(path)); /* dragregion */ if (drag) { @@ -557,6 +375,7 @@ static void renamebutton_cb(bContext *C, void *UNUSED(arg1), char *oldname) static void draw_background(FileLayout *layout, View2D *v2d) { + const int item_height = layout->tile_h + (2 * layout->tile_border_y); int i; int sy; @@ -565,9 +384,11 @@ static void draw_background(FileLayout *layout, View2D *v2d) immUniformThemeColorShade(TH_BACK, -7); /* alternating flat shade background */ - for (i = 0; (i <= layout->rows); i += 2) { - sy = (int)v2d->cur.ymax - i * (layout->tile_h + 2 * layout->tile_border_y) - - layout->tile_border_y; + for (i = 2; (i <= layout->rows + 1); i += 2) { + sy = (int)v2d->cur.ymax - layout->offset_top - i * item_height - layout->tile_border_y; + + /* Offsett pattern slightly to add scroll effect. */ + sy += round_fl_to_int(item_height * (v2d->tot.ymax - v2d->cur.ymax) / item_height); immRectf(pos, v2d->cur.xmin, @@ -632,6 +453,176 @@ static void draw_dividers(FileLayout *layout, View2D *v2d) } } +static void draw_columnheader_background(const FileLayout *layout, const View2D *v2d) +{ + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, 11); + + immRectf(pos, + v2d->cur.xmin, + v2d->cur.ymax - layout->attribute_column_header_h, + v2d->cur.xmax, + v2d->cur.ymax); + + immUnbindProgram(); +} + +static void draw_columnheader_columns(const FileSelectParams *params, + FileLayout *layout, + const View2D *v2d, + const uchar text_col[4]) +{ + const float divider_pad = 0.2 * layout->attribute_column_header_h; + int sx = v2d->cur.xmin, sy = v2d->cur.ymax; + + for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; + column_type++) { + if (!file_attribute_column_type_enabled(params, column_type)) { + continue; + } + const FileAttributeColumn *column = &layout->attribute_columns[column_type]; + + /* Active sort type triangle */ + if (params->sort == column->sort_type) { + float tri_color[4]; + + rgba_uchar_to_float(tri_color, text_col); + UI_draw_icon_tri(sx + column->width - (0.3f * U.widget_unit) - + ATTRIBUTE_COLUMN_PADDING / 2.0f, + sy + (0.1f * U.widget_unit) - (layout->attribute_column_header_h / 2), + (params->flag & FILE_SORT_INVERT) ? 't' : 'v', + tri_color); + } + + file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING, + sy - layout->tile_border_y, + IFACE_(column->name), + column->width - 2 * ATTRIBUTE_COLUMN_PADDING, + layout->attribute_column_header_h - layout->tile_border_y, + UI_STYLE_TEXT_LEFT, + text_col); + + /* Separator line */ + if (column_type != COLUMN_NAME) { + uint pos = GPU_vertformat_attr_add( + immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, -10); + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, sx - 1, sy - divider_pad); + immVertex2f(pos, sx - 1, sy - layout->attribute_column_header_h + divider_pad); + immEnd(); + immUnbindProgram(); + } + + sx += column->width; + } + + /* Vertical separator lines line */ + { + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + immUniformThemeColorShade(TH_BACK, -10); + immBegin(GPU_PRIM_LINES, 4); + immVertex2f(pos, v2d->cur.xmin, sy); + immVertex2f(pos, v2d->cur.xmax, sy); + immVertex2f(pos, v2d->cur.xmin, sy - layout->attribute_column_header_h); + immVertex2f(pos, v2d->cur.xmax, sy - layout->attribute_column_header_h); + immEnd(); + immUnbindProgram(); + } +} + +/** + * Updates the stat string stored in file->entry if necessary. + */ +static const char *filelist_get_details_column_string(FileAttributeColumnType column, + const FileDirEntry *file, + const bool small_size, + const bool update_stat_strings) +{ + switch (column) { + case COLUMN_DATETIME: + if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) { + if ((file->entry->datetime_str[0] == '\0') || update_stat_strings) { + char date[FILELIST_DIRENTRY_DATE_LEN], time[FILELIST_DIRENTRY_TIME_LEN]; + bool is_today, is_yesterday; + + BLI_filelist_entry_datetime_to_string( + NULL, file->entry->time, small_size, time, date, &is_today, &is_yesterday); + + if (is_today || is_yesterday) { + BLI_strncpy(date, is_today ? N_("Today") : N_("Yesterday"), sizeof(date)); + } + BLI_snprintf( + file->entry->datetime_str, sizeof(file->entry->datetime_str), "%s %s", date, time); + } + + return file->entry->datetime_str; + } + break; + case COLUMN_SIZE: + if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || + !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { + if ((file->entry->size_str[0] == '\0') || update_stat_strings) { + BLI_filelist_entry_size_to_string( + NULL, file->entry->size, small_size, file->entry->size_str); + } + + return file->entry->size_str; + } + break; + default: + break; + } + + return NULL; +} + +static void draw_details_columns(const FileSelectParams *params, + const FileLayout *layout, + const FileDirEntry *file, + const int pos_x, + const int pos_y, + const uchar text_col[4]) +{ + const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); + const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size); + int sx = pos_x - layout->tile_border_x - (UI_UNIT_X * 0.1f), sy = pos_y; + + for (FileAttributeColumnType column_type = 0; column_type < ATTRIBUTE_COLUMN_MAX; + column_type++) { + const FileAttributeColumn *column = &layout->attribute_columns[column_type]; + + /* Name column is not a detail column (should already be drawn), always skip here. */ + if (column_type == COLUMN_NAME) { + sx += column->width; + continue; + } + if (!file_attribute_column_type_enabled(params, column_type)) { + continue; + } + + const char *str = filelist_get_details_column_string( + column_type, file, small_size, update_stat_strings); + + if (str) { + file_draw_string(sx + ATTRIBUTE_COLUMN_PADDING, + sy - layout->tile_border_y, + IFACE_(str), + column->width - 2 * ATTRIBUTE_COLUMN_PADDING, + layout->tile_h, + column->text_align, + text_col); + } + + sx += column->width; + } +} + void file_draw_list(const bContext *C, ARegion *ar) { SpaceFile *sfile = CTX_wm_space_file(C); @@ -652,18 +643,14 @@ void file_draw_list(const bContext *C, ARegion *ar) bool is_icon; eFontStyle_Align align; bool do_drag; - int column_space = 0.6f * UI_UNIT_X; unsigned char text_col[4]; - const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); - const bool update_stat_strings = small_size != SMALL_SIZE_CHECK(layout->curr_size); - const float thumb_icon_aspect = sqrtf(64.0f / (float)(params->thumbnail_size)); + const bool draw_columnheader = (params->display == FILE_VERTICALDISPLAY); + const float thumb_icon_aspect = MIN2(64.0f / (float)(params->thumbnail_size), 1.0f); numfiles = filelist_files_ensure(files); if (params->display != FILE_IMGDISPLAY) { - draw_background(layout, v2d); - draw_dividers(layout, v2d); } @@ -679,13 +666,14 @@ void file_draw_list(const bContext *C, ARegion *ar) numfiles_layout += layout->rows; } else { - numfiles_layout += layout->columns; + numfiles_layout += layout->flow_columns; } filelist_file_cache_slidingwindow_set(files, numfiles_layout); - textwidth = (FILE_IMGDISPLAY == params->display) ? layout->tile_w : - (int)layout->column_widths[COLUMN_NAME]; + textwidth = (FILE_IMGDISPLAY == params->display) ? + layout->tile_w : + round_fl_to_int(layout->attribute_columns[COLUMN_NAME].width); textheight = (int)(layout->textheight * 3.0 / 2.0 + 0.5); align = (FILE_IMGDISPLAY == params->display) ? UI_STYLE_TEXT_CENTER : UI_STYLE_TEXT_LEFT; @@ -719,11 +707,16 @@ void file_draw_list(const bContext *C, ARegion *ar) BLF_batch_draw_begin(); + UI_GetThemeColor4ubv(TH_TEXT, text_col); + for (i = offset; (i < numfiles) && (i < offset + numfiles_layout); i++) { unsigned int file_selflag; char path[FILE_MAX_LIBEXTRA]; + int padx = 0.1f * UI_UNIT_X; + int icon_ofs = 0; + ED_fileselect_layout_tilepos(layout, i, &sx, &sy); - sx += (int)(v2d->tot.xmin + 0.1f * UI_UNIT_X); + sx += (int)(v2d->tot.xmin + padx); sy = (int)(v2d->tot.ymax - sy); file = filelist_file(files, i); @@ -737,15 +730,14 @@ void file_draw_list(const bContext *C, ARegion *ar) int colorid = (file_selflag & FILE_SEL_SELECTED) ? TH_HILITE : TH_BACK; int shade = (params->highlight_file == i) || (file_selflag & FILE_SEL_HIGHLIGHTED) ? 35 : 0; + const short width = ELEM(params->display, FILE_VERTICALDISPLAY, FILE_HORIZONTALDISPLAY) ? + layout->tile_w - (2 * padx) : + layout->tile_w; BLI_assert(i == 0 || !FILENAME_IS_CURRPAR(file->relpath)); - draw_tile(sx, - sy - 1, - layout->tile_w + 4, - sfile->layout->tile_h + layout->tile_border_y, - colorid, - shade); + draw_tile( + sx, sy - 1, width, sfile->layout->tile_h + layout->tile_border_y, colorid, shade); } } UI_draw_roundbox_corner_set(UI_CNR_NONE); @@ -778,38 +770,28 @@ void file_draw_list(const bContext *C, ARegion *ar) file_draw_icon(block, path, sx, - sy - (UI_UNIT_Y / 6), + sy - layout->tile_border_y, filelist_geticon(files, i, true), ICON_DEFAULT_WIDTH_SCALE, ICON_DEFAULT_HEIGHT_SCALE, do_drag); - sx += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; + icon_ofs += ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X; } - UI_GetThemeColor4ubv(TH_TEXT, text_col); - if (file_selflag & FILE_SEL_EDITING) { uiBut *but; - short width; - - if (params->display == FILE_SHORTDISPLAY) { - width = layout->tile_w - (ICON_DEFAULT_WIDTH_SCALE + 0.2f * UI_UNIT_X); - } - else if (params->display == FILE_LONGDISPLAY) { - width = layout->column_widths[COLUMN_NAME] + (column_space * 3.5f); - } - else { - BLI_assert(params->display == FILE_IMGDISPLAY); - width = textwidth; - } + const short width = (params->display == FILE_IMGDISPLAY) ? + textwidth : + layout->attribute_columns[COLUMN_NAME].width - + ATTRIBUTE_COLUMN_PADDING; but = uiDefBut(block, UI_BTYPE_TEXT, 1, "", - sx, + sx + icon_ofs, sy - layout->tile_h - 0.15f * UI_UNIT_X, - width, + width - icon_ofs, textheight, sfile->params->renamefile, 1.0f, @@ -825,74 +807,19 @@ void file_draw_list(const bContext *C, ARegion *ar) sfile->files, file, FILE_SEL_REMOVE, FILE_SEL_EDITING, CHECK_ALL); } } - - if (!(file_selflag & FILE_SEL_EDITING)) { - int tpos = (FILE_IMGDISPLAY == params->display) ? sy - layout->tile_h + layout->textheight : - sy; - file_draw_string(sx + 1, tpos, file->name, (float)textwidth, textheight, align, text_col); - } - - sx += (int)layout->column_widths[COLUMN_NAME] + column_space; - if (params->display == FILE_SHORTDISPLAY) { - if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || - !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { - if ((file->entry->size_str[0] == '\0') || update_stat_strings) { - BLI_filelist_entry_size_to_string( - NULL, file->entry->size, small_size, file->entry->size_str); - } - file_draw_string(sx, - sy, - file->entry->size_str, - layout->column_widths[COLUMN_SIZE], - layout->tile_h, - align, - text_col); - } - sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; + else { + const int txpos = (params->display == FILE_IMGDISPLAY) ? sx : sx + 1 + icon_ofs; + const int typos = (params->display == FILE_IMGDISPLAY) ? + sy - layout->tile_h + layout->textheight : + sy - layout->tile_border_y; + const int twidth = (params->display == FILE_IMGDISPLAY) ? + textwidth : + textwidth - 1 - icon_ofs - padx - layout->tile_border_x; + file_draw_string(txpos, typos, file->name, (float)twidth, textheight, align, text_col); } - else if (params->display == FILE_LONGDISPLAY) { - if (!(file->typeflag & FILE_TYPE_BLENDERLIB) && !FILENAME_IS_CURRPAR(file->relpath)) { - if ((file->entry->date_str[0] == '\0') || update_stat_strings) { - BLI_filelist_entry_datetime_to_string( - NULL, file->entry->time, small_size, file->entry->time_str, file->entry->date_str); - } - file_draw_string(sx, - sy, - file->entry->date_str, - layout->column_widths[COLUMN_DATE], - layout->tile_h, - align, - text_col); - sx += (int)layout->column_widths[COLUMN_DATE] + column_space; - file_draw_string(sx, - sy, - file->entry->time_str, - layout->column_widths[COLUMN_TIME], - layout->tile_h, - align, - text_col); - sx += (int)layout->column_widths[COLUMN_TIME] + column_space; - } - else { - sx += (int)layout->column_widths[COLUMN_DATE] + column_space; - sx += (int)layout->column_widths[COLUMN_TIME] + column_space; - } - if ((file->typeflag & (FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) || - !(file->typeflag & (FILE_TYPE_DIR | FILE_TYPE_BLENDERLIB))) { - if ((file->entry->size_str[0] == '\0') || update_stat_strings) { - BLI_filelist_entry_size_to_string( - NULL, file->entry->size, small_size, file->entry->size_str); - } - file_draw_string(sx, - sy, - file->entry->size_str, - layout->column_widths[COLUMN_SIZE], - layout->tile_h, - align, - text_col); - } - sx += (int)layout->column_widths[COLUMN_SIZE] + column_space; + if (params->display != FILE_IMGDISPLAY) { + draw_details_columns(params, layout, file, sx, sy, text_col); } } @@ -901,5 +828,11 @@ void file_draw_list(const bContext *C, ARegion *ar) UI_block_end(C, block); UI_block_draw(C, block); + /* Draw last, on top of file list. */ + if (draw_columnheader) { + draw_columnheader_background(layout, v2d); + draw_columnheader_columns(params, layout, v2d, text_col); + } + layout->curr_size = params->thumbnail_size; } diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index bad25511dd5..61f13098783 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -30,9 +30,11 @@ struct ARegion; struct ARegionType; struct FileSelectParams; struct SpaceFile; +struct View2D; /* file_ops.c */ struct ARegion *file_tools_region(struct ScrArea *sa); +struct ARegion *file_tool_props_region(struct ScrArea *sa); /* file_draw.c */ #define TILE_BORDER_X (UI_UNIT_X / 4) @@ -42,9 +44,10 @@ struct ARegion *file_tools_region(struct ScrArea *sa); #define IMASEL_BUTTONS_HEIGHT (UI_UNIT_Y * 2) #define IMASEL_BUTTONS_MARGIN (UI_UNIT_Y / 6) +#define ATTRIBUTE_COLUMN_PADDING (0.5f * UI_UNIT_X) + #define SMALL_SIZE_CHECK(_size) ((_size) < 64) /* Related to FileSelectParams.thumbnail_size. */ -void file_draw_buttons(const bContext *C, ARegion *ar); void file_calc_previews(const bContext *C, ARegion *ar); void file_draw_list(const bContext *C, ARegion *ar); @@ -64,6 +67,7 @@ typedef enum WalkSelectDirection { } WalkSelectDirections; void FILE_OT_highlight(struct wmOperatorType *ot); +void FILE_OT_sort_column_ui_context(struct wmOperatorType *ot); void FILE_OT_select(struct wmOperatorType *ot); void FILE_OT_select_walk(struct wmOperatorType *ot); void FILE_OT_select_all(struct wmOperatorType *ot); @@ -112,6 +116,16 @@ void file_operator_to_sfile(bContext *C, struct SpaceFile *sfile, struct wmOpera /* filesel.c */ void fileselect_file_set(SpaceFile *sfile, const int index); +bool file_attribute_column_type_enabled(const FileSelectParams *params, + FileAttributeColumnType column); +bool file_attribute_column_header_is_inside(const struct View2D *v2d, + const FileLayout *layout, + int x, + int y); +FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, + const FileSelectParams *params, + FileLayout *layout, + int x); float file_string_width(const char *str); float file_font_pointsize(void); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index eb5f02b6e13..bd018581d32 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -78,7 +78,12 @@ static FileSelection find_file_mouse_rect(SpaceFile *sfile, ARegion *ar, const r BLI_rctf_rcti_copy(&rect_region_fl, rect_region); + /* Okay, manipulating v2d rects here is hacky... */ + v2d->mask.ymax -= sfile->layout->offset_top; + v2d->cur.ymax -= sfile->layout->offset_top; UI_view2d_region_to_view_rctf(v2d, &rect_region_fl, &rect_view_fl); + v2d->mask.ymax += sfile->layout->offset_top; + v2d->cur.ymax += sfile->layout->offset_top; BLI_rcti_init(&rect_view, (int)(v2d->tot.xmin + rect_view_fl.xmin), @@ -190,7 +195,6 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) const bool is_parent_dir = FILENAME_IS_PARENT(file->relpath); if (do_diropen == false) { - params->file[0] = '\0'; retval = FILE_SELECT_DIR; } /* the path is too long and we are not going up! */ @@ -262,8 +266,8 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i cur->ymax = cur->ymin + ar->winy; } /* up */ - else if (cur->ymax < rect.ymax) { - cur->ymax = rect.ymax + layout->tile_border_y; + else if ((cur->ymax - layout->offset_top) < rect.ymax) { + cur->ymax = rect.ymax + layout->tile_border_y + layout->offset_top; cur->ymin = cur->ymax - ar->winy; } /* left - also use if tile is wider than viewbounds so view is aligned to file name */ @@ -278,7 +282,7 @@ static void file_ensure_inside_viewbounds(ARegion *ar, SpaceFile *sfile, const i } else { BLI_assert(cur->xmin <= rect.xmin && cur->xmax >= rect.xmax && cur->ymin <= rect.ymin && - cur->ymax >= rect.ymax); + (cur->ymax - layout->offset_top) >= rect.ymax); changed = false; } @@ -384,7 +388,7 @@ static int file_box_select_modal(bContext *C, wmOperator *op, const wmEvent *eve if (result == OPERATOR_RUNNING_MODAL) { WM_operator_properties_border_to_rcti(op, &rect); - BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); + ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect); sel = file_selection_get(C, &rect, 0); if ((sel.first != params->sel_first) || (sel.last != params->sel_last)) { @@ -440,7 +444,7 @@ static int file_box_select_exec(bContext *C, wmOperator *op) file_deselect_all(sfile, FILE_SEL_SELECTED); } - BLI_rcti_isect(&(ar->v2d.mask), &rect, &rect); + ED_fileselect_layout_isect_rect(sfile->layout, &ar->v2d, &rect, &rect); ret = file_select(C, &rect, select ? FILE_SEL_ADD : FILE_SEL_REMOVE, false, false); @@ -493,7 +497,7 @@ static int file_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) rect.xmin = rect.xmax = event->mval[0]; rect.ymin = rect.ymax = event->mval[1]; - if (!BLI_rcti_isect_pt(&ar->v2d.mask, rect.xmin, rect.ymin)) { + if (!ED_fileselect_layout_is_inside_pt(sfile->layout, &ar->v2d, rect.xmin, rect.ymin)) { return OPERATOR_CANCELLED; } @@ -691,7 +695,7 @@ static bool file_walk_select_do(bContext *C, if (has_selection) { ARegion *ar = CTX_wm_region(C); FileLayout *layout = ED_fileselect_get_layout(sfile, ar); - const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->columns; + const int idx_shift = (layout->flag & FILE_LAYOUT_HOR) ? layout->rows : layout->flow_columns; if ((layout->flag & FILE_LAYOUT_HOR && direction == FILE_SELECT_WALK_UP) || (layout->flag & FILE_LAYOUT_VER && direction == FILE_SELECT_WALK_LEFT)) { @@ -1185,7 +1189,7 @@ int file_highlight_set(SpaceFile *sfile, ARegion *ar, int mx, int my) mx -= ar->winrct.xmin; my -= ar->winrct.ymin; - if (BLI_rcti_isect_pt(&ar->v2d.mask, mx, my)) { + if (ED_fileselect_layout_is_inside_pt(sfile->layout, v2d, mx, my)) { float fx, fy; int highlight_file; @@ -1234,6 +1238,53 @@ void FILE_OT_highlight(struct wmOperatorType *ot) ot->poll = ED_operator_file_active; } +static int file_column_sort_ui_context_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *event) +{ + const ARegion *ar = CTX_wm_region(C); + SpaceFile *sfile = CTX_wm_space_file(C); + + if (file_attribute_column_header_is_inside( + &ar->v2d, sfile->layout, event->mval[0], event->mval[1])) { + const FileAttributeColumnType column_type = file_attribute_column_type_find_isect( + &ar->v2d, sfile->params, sfile->layout, event->mval[0]); + + 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; +} + int file_cancel_exec(bContext *C, wmOperator *UNUSED(unused)) { wmWindowManager *wm = CTX_wm_manager(C); @@ -1713,7 +1764,7 @@ static int file_smoothscroll_invoke(bContext *C, wmOperator *UNUSED(op), const w /* Number of items in a block (i.e. lines in a column in horizontal layout, or columns in a line * in vertical layout). */ - const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->columns; + const int items_block_size = is_horizontal ? sfile->layout->rows : sfile->layout->flow_columns; /* Scroll offset is the first file in the row/column we are editing in. */ if (sfile->scroll_offset == 0) { @@ -1998,7 +2049,6 @@ void FILE_OT_directory_new(struct wmOperatorType *ot) ot->idname = "FILE_OT_directory_new"; /* api callbacks */ - ot->invoke = WM_operator_confirm; ot->exec = file_directory_new_exec; ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ @@ -2260,10 +2310,29 @@ ARegion *file_tools_region(ScrArea *sa) arnew->regiontype = RGN_TYPE_TOOLS; arnew->alignment = RGN_ALIGN_LEFT; - ar = MEM_callocN(sizeof(ARegion), "tool props for file"); - BLI_insertlinkafter(&sa->regionbase, arnew, ar); - ar->regiontype = RGN_TYPE_TOOL_PROPS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + return arnew; +} + +ARegion *file_tool_props_region(ScrArea *sa) +{ + ARegion *ar, *arnew; + + if ((ar = BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS)) != NULL) { + return ar; + } + + /* add subdiv level; after execute region */ + ar = BKE_area_find_region_type(sa, RGN_TYPE_EXECUTE); + + /* is error! */ + if (ar == NULL) { + return NULL; + } + + arnew = MEM_callocN(sizeof(ARegion), "tool props for file"); + BLI_insertlinkafter(&sa->regionbase, ar, arnew); + arnew->regiontype = RGN_TYPE_TOOL_PROPS; + arnew->alignment = RGN_ALIGN_RIGHT; return arnew; } @@ -2292,6 +2361,17 @@ void FILE_OT_bookmark_toggle(struct wmOperatorType *ot) ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ } +static bool file_filenum_poll(bContext *C) +{ + SpaceFile *sfile = CTX_wm_space_file(C); + + if (!ED_operator_file_active(C)) { + return false; + } + + return sfile->params && (sfile->params->action_type == FILE_SAVE); +} + /** * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add. */ @@ -2349,7 +2429,7 @@ void FILE_OT_filenum(struct wmOperatorType *ot) /* api callbacks */ ot->exec = file_filenum_exec; - ot->poll = ED_operator_file_active; /* <- important, handler is on window level */ + ot->poll = file_filenum_poll; /* props */ RNA_def_int(ot->srna, "increment", 1, -100, 100, "Increment", "", -100, 100); diff --git a/source/blender/editors/space_file/file_panels.c b/source/blender/editors/space_file/file_panels.c index d9a6e70121f..b41358f575f 100644 --- a/source/blender/editors/space_file/file_panels.c +++ b/source/blender/editors/space_file/file_panels.c @@ -103,6 +103,7 @@ void file_panels_register(ARegionType *art) strcpy(pt->idname, "FILE_PT_operator"); strcpy(pt->label, N_("Operator")); strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + pt->flag = PNL_NO_HEADER; pt->poll = file_panel_operator_poll; pt->draw_header = file_panel_operator_header; pt->draw = file_panel_operator; diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index ee86a583974..fdc101f3d82 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -329,25 +329,20 @@ enum { FL_IS_PENDING = 1 << 2, FL_NEED_SORTING = 1 << 3, FL_NEED_FILTERING = 1 << 4, + FL_SORT_INVERT = 1 << 5, }; -#define SPECIAL_IMG_SIZE 48 -#define SPECIAL_IMG_ROWS 4 -#define SPECIAL_IMG_COLS 4 +#define SPECIAL_IMG_SIZE 256 +#define SPECIAL_IMG_ROWS 1 +#define SPECIAL_IMG_COLS 6 enum { - SPECIAL_IMG_FOLDER = 0, - SPECIAL_IMG_PARENT = 1, - SPECIAL_IMG_REFRESH = 2, - SPECIAL_IMG_BLENDFILE = 3, - SPECIAL_IMG_SOUNDFILE = 4, - SPECIAL_IMG_MOVIEFILE = 5, - SPECIAL_IMG_PYTHONFILE = 6, - SPECIAL_IMG_TEXTFILE = 7, - SPECIAL_IMG_FONTFILE = 8, - SPECIAL_IMG_UNKNOWNFILE = 9, - SPECIAL_IMG_LOADING = 10, - SPECIAL_IMG_BACKUP = 11, + SPECIAL_IMG_DOCUMENT = 0, + SPECIAL_IMG_FOLDER = 1, + SPECIAL_IMG_PARENT = 2, + SPECIAL_IMG_DRIVE_FIXED = 3, + SPECIAL_IMG_DRIVE_ATTACHED = 4, + SPECIAL_IMG_DRIVE_REMOTE = 5, SPECIAL_IMG_MAX, }; @@ -369,6 +364,19 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size); /* ********** Sort helpers ********** */ +struct FileSortData { + bool inverted; +}; + +static int compare_apply_inverted(int val, const struct FileSortData *sort_data) +{ + return sort_data->inverted ? -val : val; +} + +/** + * Handles inverted sorting itself (currently there's nothing to invert), so if this returns non-0, + * it should be used as-is and not inverted. + */ static int compare_direntry_generic(const FileListInternEntry *entry1, const FileListInternEntry *entry2) { @@ -420,10 +428,11 @@ static int compare_direntry_generic(const FileListInternEntry *entry1, return 0; } -static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2) +static int compare_name(void *user_data, const void *a1, const void *a2) { const FileListInternEntry *entry1 = a1; const FileListInternEntry *entry2 = a2; + const struct FileSortData *sort_data = user_data; char *name1, *name2; int ret; @@ -434,13 +443,14 @@ static int compare_name(void *UNUSED(user_data), const void *a1, const void *a2) name1 = entry1->name; name2 = entry2->name; - return BLI_strcasecmp_natural(name1, name2); + return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data); } -static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2) +static int compare_date(void *user_data, const void *a1, const void *a2) { const FileListInternEntry *entry1 = a1; const FileListInternEntry *entry2 = a2; + const struct FileSortData *sort_data = user_data; char *name1, *name2; int64_t time1, time2; int ret; @@ -452,22 +462,23 @@ static int compare_date(void *UNUSED(user_data), const void *a1, const void *a2) time1 = (int64_t)entry1->st.st_mtime; time2 = (int64_t)entry2->st.st_mtime; if (time1 < time2) { - return 1; + return compare_apply_inverted(1, sort_data); } if (time1 > time2) { - return -1; + return compare_apply_inverted(-1, sort_data); } name1 = entry1->name; name2 = entry2->name; - return BLI_strcasecmp_natural(name1, name2); + return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data); } -static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2) +static int compare_size(void *user_data, const void *a1, const void *a2) { const FileListInternEntry *entry1 = a1; const FileListInternEntry *entry2 = a2; + const struct FileSortData *sort_data = user_data; char *name1, *name2; uint64_t size1, size2; int ret; @@ -479,22 +490,23 @@ static int compare_size(void *UNUSED(user_data), const void *a1, const void *a2) size1 = entry1->st.st_size; size2 = entry2->st.st_size; if (size1 < size2) { - return 1; + return compare_apply_inverted(1, sort_data); } if (size1 > size2) { - return -1; + return compare_apply_inverted(-1, sort_data); } name1 = entry1->name; name2 = entry2->name; - return BLI_strcasecmp_natural(name1, name2); + return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data); } -static int compare_extension(void *UNUSED(user_data), const void *a1, const void *a2) +static int compare_extension(void *user_data, const void *a1, const void *a2) { const FileListInternEntry *entry1 = a1; const FileListInternEntry *entry2 = a2; + const struct FileSortData *sort_data = user_data; char *name1, *name2; int ret; @@ -516,10 +528,10 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void return -1; } if (entry1->blentype < entry2->blentype) { - return -1; + return compare_apply_inverted(-1, sort_data); } if (entry1->blentype > entry2->blentype) { - return 1; + return compare_apply_inverted(1, sort_data); } } else { @@ -539,48 +551,58 @@ static int compare_extension(void *UNUSED(user_data), const void *a1, const void } if ((ret = BLI_strcasecmp(sufix1, sufix2))) { - return ret; + return compare_apply_inverted(ret, sort_data); } } name1 = entry1->name; name2 = entry2->name; - return BLI_strcasecmp_natural(name1, name2); + return compare_apply_inverted(BLI_strcasecmp_natural(name1, name2), sort_data); } void filelist_sort(struct FileList *filelist) { if ((filelist->flags & FL_NEED_SORTING) && (filelist->sort != FILE_SORT_NONE)) { + void *sort_cb = NULL; + switch (filelist->sort) { case FILE_SORT_ALPHA: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_name, NULL); + sort_cb = compare_name; break; case FILE_SORT_TIME: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_date, NULL); + sort_cb = compare_date; break; case FILE_SORT_SIZE: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_size, NULL); + sort_cb = compare_size; break; case FILE_SORT_EXTENSION: - BLI_listbase_sort_r(&filelist->filelist_intern.entries, compare_extension, NULL); + sort_cb = compare_extension; break; case FILE_SORT_NONE: /* Should never reach this point! */ default: BLI_assert(0); break; } + BLI_listbase_sort_r( + &filelist->filelist_intern.entries, + sort_cb, + &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0}); filelist_filter_clear(filelist); filelist->flags &= ~FL_NEED_SORTING; } } -void filelist_setsorting(struct FileList *filelist, const short sort) +void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort) { - if (filelist->sort != sort) { + const bool was_invert_sort = filelist->flags & FL_SORT_INVERT; + + if ((filelist->sort != sort) || (was_invert_sort != invert_sort)) { filelist->sort = sort; filelist->flags |= FL_NEED_SORTING; + filelist->flags = invert_sort ? (filelist->flags | FL_SORT_INVERT) : + (filelist->flags & ~FL_SORT_INVERT); } } @@ -635,9 +657,9 @@ static bool is_filtered_file(FileListInternEntry *file, { bool is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { /* We only check for types if some type are enabled in filtering. */ - if (filter->filter) { + if (filter->filter && (filter->flags & FLF_DO_FILTER)) { if (file->typeflag & FILE_TYPE_DIR) { if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { @@ -657,6 +679,7 @@ static bool is_filtered_file(FileListInternEntry *file, } } } + /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ if (is_filtered && (filter->filter_search[0] != '\0')) { if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { is_filtered = false; @@ -676,9 +699,9 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis if (BLO_library_path_explode(path, dir, &group, &name)) { is_filtered = !is_hidden_file(file->relpath, filter); - if (is_filtered && (filter->flags & FLF_DO_FILTER) && !FILENAME_IS_CURRPAR(file->relpath)) { + if (is_filtered && !FILENAME_IS_CURRPAR(file->relpath)) { /* We only check for types if some type are enabled in filtering. */ - if (filter->filter || filter->filter_id) { + if ((filter->filter || filter->filter_id) && (filter->flags & FLF_DO_FILTER)) { if (file->typeflag & FILE_TYPE_DIR) { if (file->typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER | FILE_TYPE_BLENDER_BACKUP)) { @@ -704,6 +727,7 @@ static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileLis } } } + /* If there's a filter string, apply it as filter even if FLF_DO_FILTER is not set. */ if (is_filtered && (filter->filter_search[0] != '\0')) { if (fnmatch(filter->filter_search, file->relpath, FNM_CASEFOLD) != 0) { is_filtered = false; @@ -904,42 +928,12 @@ static ImBuf *filelist_geticon_image_ex(const unsigned int typeflag, const char if (FILENAME_IS_PARENT(relpath)) { ibuf = gSpecialFileImages[SPECIAL_IMG_PARENT]; } - else if (FILENAME_IS_CURRENT(relpath)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_REFRESH]; - } else { ibuf = gSpecialFileImages[SPECIAL_IMG_FOLDER]; } } - else if (typeflag & FILE_TYPE_BLENDER) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BLENDFILE]; - } - else if (typeflag & FILE_TYPE_BLENDERLIB) { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; - } - else if (typeflag & (FILE_TYPE_MOVIE)) { - ibuf = gSpecialFileImages[SPECIAL_IMG_MOVIEFILE]; - } - else if (typeflag & FILE_TYPE_SOUND) { - ibuf = gSpecialFileImages[SPECIAL_IMG_SOUNDFILE]; - } - else if (typeflag & FILE_TYPE_PYSCRIPT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_PYTHONFILE]; - } - else if (typeflag & FILE_TYPE_FTFONT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_FONTFILE]; - } - else if (typeflag & FILE_TYPE_TEXT) { - ibuf = gSpecialFileImages[SPECIAL_IMG_TEXTFILE]; - } - else if (typeflag & FILE_TYPE_IMAGE) { - ibuf = gSpecialFileImages[SPECIAL_IMG_LOADING]; - } - else if (typeflag & FILE_TYPE_BLENDER_BACKUP) { - ibuf = gSpecialFileImages[SPECIAL_IMG_BACKUP]; - } else { - ibuf = gSpecialFileImages[SPECIAL_IMG_UNKNOWNFILE]; + ibuf = gSpecialFileImages[SPECIAL_IMG_DOCUMENT]; } return ibuf; @@ -1001,10 +995,13 @@ static int filelist_geticon_ex(const int typeflag, return ICON_FILE_BLANK; } else if (typeflag & FILE_TYPE_COLLADA) { - return ICON_FILE_BLANK; + return ICON_FILE_3D; } else if (typeflag & FILE_TYPE_ALEMBIC) { - return ICON_FILE_BLANK; + return ICON_FILE_3D; + } + else if (typeflag & FILE_TYPE_OBJECT_IO) { + return ICON_FILE_3D; } else if (typeflag & FILE_TYPE_TEXT) { return ICON_FILE_TEXT; @@ -1243,7 +1240,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache) BLI_task_pool_cancel(cache->previews_pool); while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { - // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); + // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, + // preview->img); if (preview->img) { IMB_freeImBuf(preview->img); } @@ -2128,6 +2126,9 @@ int ED_path_extension_type(const char *path) else if (BLI_path_extension_check(path, ".abc")) { return FILE_TYPE_ALEMBIC; } + else if (BLI_path_extension_check_n(path, ".obj", ".3ds", ".fbx", ".glb", ".gltf", NULL)) { + return FILE_TYPE_OBJECT_IO; + } else if (BLI_path_extension_check_array(path, imb_ext_image)) { return FILE_TYPE_IMAGE; } @@ -2177,9 +2178,9 @@ int ED_file_extension_icon(const char *path) case FILE_TYPE_BTX: return ICON_FILE_BLANK; case FILE_TYPE_COLLADA: - return ICON_FILE_BLANK; case FILE_TYPE_ALEMBIC: - return ICON_FILE_BLANK; + case FILE_TYPE_OBJECT_IO: + return ICON_FILE_3D; case FILE_TYPE_TEXT: return ICON_FILE_TEXT; default: diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index caf77246797..9af0b7d623f 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -55,7 +55,7 @@ void folderlist_pushdir(struct ListBase *folderlist, const char *dir); const char *folderlist_peeklastdir(struct ListBase *folderdist); int folderlist_clear_next(struct SpaceFile *sfile); -void filelist_setsorting(struct FileList *filelist, const short sort); +void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort); void filelist_sort(struct FileList *filelist); void filelist_setfilter_options(struct FileList *filelist, diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index db42d007b8e..3223fe0c6ce 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -49,6 +49,8 @@ #include "BLI_utildefines.h" #include "BLI_fnmatch.h" +#include "BLT_translation.h" + #include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_main.h" @@ -69,6 +71,8 @@ #include "file_intern.h" #include "filelist.h" +#define VERTLIST_MAJORCOLUMN_WIDTH (25 * UI_UNIT_X) + FileSelectParams *ED_fileselect_get_params(struct SpaceFile *sfile) { if (!sfile->params) { @@ -99,6 +103,8 @@ short ED_fileselect_set_params(SpaceFile *sfile) sfile->params->filter_glob[0] = '\0'; /* set the default thumbnails size */ sfile->params->thumbnail_size = 128; + /* Show size column by default. */ + sfile->params->details_flags = FILE_DETAILS_SIZE | FILE_DETAILS_DATETIME; } params = sfile->params; @@ -161,6 +167,10 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->flag &= ~FILE_DIRSEL_ONLY; } + if ((prop = RNA_struct_find_property(op->ptr, "hide_props_region"))) { + params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_HIDE_TOOL_PROPS : 0; + } + params->filter = 0; if ((prop = RNA_struct_find_property(op->ptr, "filter_blender"))) { params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_BLENDER : 0; @@ -261,6 +271,10 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->sort = FILE_SORT_ALPHA; } + if ((prop = RNA_struct_find_property(op->ptr, "action_type"))) { + params->action_type = RNA_property_enum_get(op->ptr, prop); + } + if (params->display == FILE_DEFAULTDISPLAY) { if (params->display_previous == FILE_DEFAULTDISPLAY) { if (U.uiflag & USER_SHOW_THUMBNAILS) { @@ -268,11 +282,11 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->display = FILE_IMGDISPLAY; } else { - params->display = FILE_SHORTDISPLAY; + params->display = FILE_VERTICALDISPLAY; } } else { - params->display = FILE_SHORTDISPLAY; + params->display = FILE_VERTICALDISPLAY; } } else { @@ -293,7 +307,7 @@ short ED_fileselect_set_params(SpaceFile *sfile) params->type = FILE_UNIX; params->flag |= FILE_HIDE_DOT; params->flag &= ~FILE_DIRSEL_ONLY; - params->display = FILE_SHORTDISPLAY; + params->display = FILE_VERTICALDISPLAY; params->display_previous = FILE_DEFAULTDISPLAY; params->sort = FILE_SORT_ALPHA; params->filter = 0; @@ -344,7 +358,7 @@ void ED_fileselect_reset_params(SpaceFile *sfile) void fileselect_file_set(SpaceFile *sfile, const int index) { const struct FileDirEntry *file = filelist_file(sfile->files, index); - if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_FOLDER)) { + if (file && file->relpath && file->relpath[0] && !(file->typeflag & FILE_TYPE_DIR)) { BLI_strncpy(sfile->params->file, file->relpath, FILE_MAXFILE); } } @@ -372,10 +386,10 @@ int ED_fileselect_layout_numfiles(FileLayout *layout, ARegion *ar) } else { const int y_item = layout->tile_h + (2 * layout->tile_border_y); - const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)); + const int y_view = (int)(BLI_rctf_size_y(&ar->v2d.cur)) - layout->offset_top; const int y_over = y_item - (y_view % y_item); numfiles = (int)((float)(y_view + y_over) / (float)(y_item)); - return numfiles * layout->columns; + return numfiles * layout->flow_columns; } } @@ -395,19 +409,19 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r } colmin = (rect->xmin) / (layout->tile_w + 2 * layout->tile_border_x); - rowmin = (rect->ymin) / (layout->tile_h + 2 * layout->tile_border_y); + rowmin = (rect->ymin - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y); colmax = (rect->xmax) / (layout->tile_w + 2 * layout->tile_border_x); - rowmax = (rect->ymax) / (layout->tile_h + 2 * layout->tile_border_y); + rowmax = (rect->ymax - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y); - if (is_inside(colmin, rowmin, layout->columns, layout->rows) || - is_inside(colmax, rowmax, layout->columns, layout->rows)) { - CLAMP(colmin, 0, layout->columns - 1); + if (is_inside(colmin, rowmin, layout->flow_columns, layout->rows) || + is_inside(colmax, rowmax, layout->flow_columns, layout->rows)) { + CLAMP(colmin, 0, layout->flow_columns - 1); CLAMP(rowmin, 0, layout->rows - 1); - CLAMP(colmax, 0, layout->columns - 1); + CLAMP(colmax, 0, layout->flow_columns - 1); CLAMP(rowmax, 0, layout->rows - 1); } - if ((colmin > layout->columns - 1) || (rowmin > layout->rows - 1)) { + if ((colmin > layout->flow_columns - 1) || (rowmin > layout->rows - 1)) { sel.first = -1; } else { @@ -415,10 +429,10 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r sel.first = layout->rows * colmin + rowmin; } else { - sel.first = colmin + layout->columns * rowmin; + sel.first = colmin + layout->flow_columns * rowmin; } } - if ((colmax > layout->columns - 1) || (rowmax > layout->rows - 1)) { + if ((colmax > layout->flow_columns - 1) || (rowmax > layout->rows - 1)) { sel.last = -1; } else { @@ -426,7 +440,7 @@ FileSelection ED_fileselect_layout_offset_rect(FileLayout *layout, const rcti *r sel.last = layout->rows * colmax + rowmax; } else { - sel.last = colmax + layout->columns * rowmax; + sel.last = colmax + layout->flow_columns * rowmax; } } @@ -443,9 +457,9 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y) } offsetx = (x) / (layout->tile_w + 2 * layout->tile_border_x); - offsety = (y) / (layout->tile_h + 2 * layout->tile_border_y); + offsety = (y - layout->offset_top) / (layout->tile_h + 2 * layout->tile_border_y); - if (offsetx > layout->columns - 1) { + if (offsetx > layout->flow_columns - 1) { return -1; } if (offsety > layout->rows - 1) { @@ -456,25 +470,121 @@ int ED_fileselect_layout_offset(FileLayout *layout, int x, int y) active_file = layout->rows * offsetx + offsety; } else { - active_file = offsetx + layout->columns * offsety; + active_file = offsetx + layout->flow_columns * offsety; } return active_file; } +/** + * Get the currently visible bounds of the layout in screen space. Matches View2D.mask minus the + * top column-header row. + */ +void ED_fileselect_layout_maskrect(const FileLayout *layout, const View2D *v2d, rcti *r_rect) +{ + *r_rect = v2d->mask; + r_rect->ymax -= layout->offset_top; +} + +bool ED_fileselect_layout_is_inside_pt(const FileLayout *layout, const View2D *v2d, int x, int y) +{ + rcti maskrect; + ED_fileselect_layout_maskrect(layout, v2d, &maskrect); + return BLI_rcti_isect_pt(&maskrect, x, y); +} + +bool ED_fileselect_layout_isect_rect(const FileLayout *layout, + const View2D *v2d, + const rcti *rect, + rcti *r_dst) +{ + rcti maskrect; + ED_fileselect_layout_maskrect(layout, v2d, &maskrect); + return BLI_rcti_isect(&maskrect, rect, r_dst); +} + void ED_fileselect_layout_tilepos(FileLayout *layout, int tile, int *x, int *y) { if (layout->flag == FILE_LAYOUT_HOR) { *x = layout->tile_border_x + (tile / layout->rows) * (layout->tile_w + 2 * layout->tile_border_x); - *y = layout->tile_border_y + + *y = layout->offset_top + layout->tile_border_y + (tile % layout->rows) * (layout->tile_h + 2 * layout->tile_border_y); } else { *x = layout->tile_border_x + - ((tile) % layout->columns) * (layout->tile_w + 2 * layout->tile_border_x); - *y = layout->tile_border_y + - ((tile) / layout->columns) * (layout->tile_h + 2 * layout->tile_border_y); + ((tile) % layout->flow_columns) * (layout->tile_w + 2 * layout->tile_border_x); + *y = layout->offset_top + layout->tile_border_y + + ((tile) / layout->flow_columns) * (layout->tile_h + 2 * layout->tile_border_y); + } +} + +/** + * Check if the region coordinate defined by \a x and \a y are inside the column header. + */ +bool file_attribute_column_header_is_inside(const View2D *v2d, + const FileLayout *layout, + int x, + int y) +{ + rcti header_rect = v2d->mask; + header_rect.ymin = header_rect.ymax - layout->attribute_column_header_h; + return BLI_rcti_isect_pt(&header_rect, x, y); +} + +bool file_attribute_column_type_enabled(const FileSelectParams *params, + FileAttributeColumnType column) +{ + switch (column) { + case COLUMN_NAME: + /* Always enabled */ + return true; + case COLUMN_DATETIME: + return (params->details_flags & FILE_DETAILS_DATETIME) != 0; + case COLUMN_SIZE: + return (params->details_flags & FILE_DETAILS_SIZE) != 0; + default: + return false; + } +} + +/** + * Find the column type at region coordinate given by \a x (y doesn't matter for this). + */ +FileAttributeColumnType file_attribute_column_type_find_isect(const View2D *v2d, + const FileSelectParams *params, + FileLayout *layout, + int x) +{ + float mx, my; + int offset_tile; + + UI_view2d_region_to_view(v2d, x, v2d->mask.ymax - layout->offset_top - 1, &mx, &my); + offset_tile = ED_fileselect_layout_offset( + layout, (int)(v2d->tot.xmin + mx), (int)(v2d->tot.ymax - my)); + if (offset_tile > -1) { + int tile_x, tile_y; + int pos_x = 0; + int rel_x; /* x relative to the hovered tile */ + + ED_fileselect_layout_tilepos(layout, offset_tile, &tile_x, &tile_y); + /* Column header drawing doesn't use left tile border, so subtract it. */ + rel_x = mx - (tile_x - layout->tile_border_x); + + for (FileAttributeColumnType column = 0; column < ATTRIBUTE_COLUMN_MAX; column++) { + if (!file_attribute_column_type_enabled(params, column)) { + continue; + } + const int width = layout->attribute_columns[column].width; + + if (IN_RANGE(rel_x, pos_x, pos_x + width)) { + return column; + } + + pos_x += width; + } } + + return COLUMN_NONE; } float file_string_width(const char *str) @@ -512,20 +622,52 @@ float file_font_pointsize(void) #endif } -static void column_widths(FileSelectParams *params, struct FileLayout *layout) +static void file_attribute_columns_widths(const FileSelectParams *params, FileLayout *layout) { - int i; + FileAttributeColumn *columns = layout->attribute_columns; const bool small_size = SMALL_SIZE_CHECK(params->thumbnail_size); + const int pad = small_size ? 0 : ATTRIBUTE_COLUMN_PADDING * 2; - for (i = 0; i < MAX_FILE_COLUMN; ++i) { - layout->column_widths[i] = 0; + for (int i = 0; i < ATTRIBUTE_COLUMN_MAX; ++i) { + layout->attribute_columns[i].width = 0; } - layout->column_widths[COLUMN_NAME] = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X; /* Biggest possible reasonable values... */ - layout->column_widths[COLUMN_DATE] = file_string_width(small_size ? "23/08/89" : "23-Dec-89"); - layout->column_widths[COLUMN_TIME] = file_string_width("23:59"); - layout->column_widths[COLUMN_SIZE] = file_string_width(small_size ? "98.7 M" : "98.7 MiB"); + columns[COLUMN_DATETIME].width = file_string_width(small_size ? "23/08/89" : + "23 Dec 6789, 23:59") + + pad; + columns[COLUMN_SIZE].width = file_string_width(small_size ? "98.7 M" : "098.7 MB") + pad; + if (params->display == FILE_IMGDISPLAY) { + columns[COLUMN_NAME].width = ((float)params->thumbnail_size / 8.0f) * UI_UNIT_X; + } + /* Name column uses remaining width */ + else { + int remwidth = layout->tile_w; + for (FileAttributeColumnType column_type = ATTRIBUTE_COLUMN_MAX - 1; column_type >= 0; + column_type--) { + if ((column_type == COLUMN_NAME) || + !file_attribute_column_type_enabled(params, column_type)) { + continue; + } + remwidth -= columns[column_type].width; + } + columns[COLUMN_NAME].width = remwidth; + } +} + +static void file_attribute_columns_init(const FileSelectParams *params, FileLayout *layout) +{ + file_attribute_columns_widths(params, layout); + + layout->attribute_columns[COLUMN_NAME].name = N_("Name"); + layout->attribute_columns[COLUMN_NAME].sort_type = FILE_SORT_ALPHA; + layout->attribute_columns[COLUMN_NAME].text_align = UI_STYLE_TEXT_LEFT; + layout->attribute_columns[COLUMN_DATETIME].name = N_("Date Modified"); + layout->attribute_columns[COLUMN_DATETIME].sort_type = FILE_SORT_TIME; + layout->attribute_columns[COLUMN_DATETIME].text_align = UI_STYLE_TEXT_LEFT; + layout->attribute_columns[COLUMN_SIZE].name = N_("Size"); + layout->attribute_columns[COLUMN_SIZE].sort_type = FILE_SORT_SIZE; + layout->attribute_columns[COLUMN_SIZE].text_align = UI_STYLE_TEXT_RIGHT; } void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) @@ -533,7 +675,6 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) FileSelectParams *params = ED_fileselect_get_params(sfile); FileLayout *layout = NULL; View2D *v2d = &ar->v2d; - int maxlen = 0; int numfiles; int textheight; @@ -560,57 +701,66 @@ void ED_fileselect_init_layout(struct SpaceFile *sfile, ARegion *ar) layout->tile_w = layout->prv_w + 2 * layout->prv_border_x; layout->tile_h = layout->prv_h + 2 * layout->prv_border_y + textheight; layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x); - layout->columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x); - if (layout->columns > 0) { - layout->rows = numfiles / layout->columns + 1; // XXX dirty, modulo is zero + layout->flow_columns = layout->width / (layout->tile_w + 2 * layout->tile_border_x); + layout->attribute_column_header_h = 0; + layout->offset_top = 0; + if (layout->flow_columns > 0) { + layout->rows = numfiles / layout->flow_columns + 1; // XXX dirty, modulo is zero } else { - layout->columns = 1; + layout->flow_columns = 1; layout->rows = numfiles + 1; // XXX dirty, modulo is zero } layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) + - layout->tile_border_y * 2; + layout->tile_border_y * 2 - layout->offset_top; layout->flag = FILE_LAYOUT_VER; } - else { - int column_space = 0.6f * UI_UNIT_X; - int column_icon_space = 0.2f * UI_UNIT_X; + else if (params->display == FILE_VERTICALDISPLAY) { + int rowcount; - layout->prv_w = 0; - layout->prv_h = 0; + layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; + layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; + layout->tile_border_x = 0.4f * UI_UNIT_X; + layout->tile_border_y = 0.1f * UI_UNIT_Y; + layout->tile_h = textheight * 3 / 2; + layout->width = (int)(BLI_rctf_size_x(&v2d->cur) - 2 * layout->tile_border_x); + layout->tile_w = layout->width; + layout->flow_columns = 1; + layout->attribute_column_header_h = layout->tile_h * 1.2f + 2 * layout->tile_border_y; + layout->offset_top = layout->attribute_column_header_h; + rowcount = (int)(BLI_rctf_size_y(&v2d->cur) - layout->offset_top - 2 * layout->tile_border_y) / + (layout->tile_h + 2 * layout->tile_border_y); + file_attribute_columns_init(params, layout); + + layout->rows = MAX2(rowcount, numfiles); + BLI_assert(layout->rows != 0); + layout->height = sfile->layout->rows * (layout->tile_h + 2 * layout->tile_border_y) + + layout->tile_border_y * 2 + layout->offset_top; + layout->flag = FILE_LAYOUT_VER; + } + else if (params->display == FILE_HORIZONTALDISPLAY) { + layout->prv_w = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_X; + layout->prv_h = ((float)params->thumbnail_size / 20.0f) * UI_UNIT_Y; layout->tile_border_x = 0.4f * UI_UNIT_X; layout->tile_border_y = 0.1f * UI_UNIT_Y; - layout->prv_border_x = 0; - layout->prv_border_y = 0; layout->tile_h = textheight * 3 / 2; + layout->attribute_column_header_h = 0; + layout->offset_top = layout->attribute_column_header_h; layout->height = (int)(BLI_rctf_size_y(&v2d->cur) - 2 * layout->tile_border_y); /* Padding by full scrollbar H is too much, can overlap tile border Y. */ layout->rows = (layout->height - V2D_SCROLL_HEIGHT + layout->tile_border_y) / (layout->tile_h + 2 * layout->tile_border_y); + layout->tile_w = VERTLIST_MAJORCOLUMN_WIDTH; + file_attribute_columns_init(params, layout); - column_widths(params, layout); - - if (params->display == FILE_SHORTDISPLAY) { - maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space + - (int)layout->column_widths[COLUMN_NAME] + column_space + - (int)layout->column_widths[COLUMN_SIZE] + column_space; - } - else { - maxlen = ICON_DEFAULT_WIDTH_SCALE + column_icon_space + - (int)layout->column_widths[COLUMN_NAME] + column_space + - (int)layout->column_widths[COLUMN_DATE] + column_space + - (int)layout->column_widths[COLUMN_TIME] + column_space + - (int)layout->column_widths[COLUMN_SIZE] + column_space; - } - layout->tile_w = maxlen; if (layout->rows > 0) { - layout->columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero + layout->flow_columns = numfiles / layout->rows + 1; // XXX dirty, modulo is zero } else { layout->rows = 1; - layout->columns = numfiles + 1; // XXX dirty, modulo is zero + layout->flow_columns = numfiles + 1; // XXX dirty, modulo is zero } - layout->width = sfile->layout->columns * (layout->tile_w + 2 * layout->tile_border_x) + + layout->width = sfile->layout->flow_columns * (layout->tile_w + 2 * layout->tile_border_x) + layout->tile_border_x * 2; layout->flag = FILE_LAYOUT_HOR; } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 1fd878e4662..1befdd52d7d 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -72,23 +72,40 @@ static SpaceLink *file_new(const ScrArea *UNUSED(area), const Scene *UNUSED(scen /* Ignore user preference "USER_HEADER_BOTTOM" here (always show top for new types). */ ar->alignment = RGN_ALIGN_TOP; + /* ui list region */ + ar = MEM_callocN(sizeof(ARegion), "ui region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_UI; + ar->alignment = RGN_ALIGN_TOP; + ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + /* Tools region */ ar = MEM_callocN(sizeof(ARegion), "tools region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_TOOLS; ar->alignment = RGN_ALIGN_LEFT; + /* Tools region (lower split region) */ + ar = MEM_callocN(sizeof(ARegion), "lower tools region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_TOOLS; + ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; + ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + + /* Execute region */ + ar = MEM_callocN(sizeof(ARegion), "execute region for file"); + BLI_addtail(&sfile->regionbase, ar); + ar->regiontype = RGN_TYPE_EXECUTE; + ar->alignment = RGN_ALIGN_BOTTOM; + ar->flag |= RGN_FLAG_DYNAMIC_SIZE; + /* Tool props region is added as needed. */ +#if 0 /* Tool props (aka operator) region */ ar = MEM_callocN(sizeof(ARegion), "tool props region for file"); BLI_addtail(&sfile->regionbase, ar); ar->regiontype = RGN_TYPE_TOOL_PROPS; - ar->alignment = RGN_ALIGN_BOTTOM | RGN_SPLIT_PREV; - - /* ui list region */ - ar = MEM_callocN(sizeof(ARegion), "ui region for file"); - BLI_addtail(&sfile->regionbase, ar); - ar->regiontype = RGN_TYPE_UI; - ar->alignment = RGN_ALIGN_TOP; + ar->alignment = RGN_ALIGN_RIGHT; +#endif /* main region */ ar = MEM_callocN(sizeof(ARegion), "main region for file"); @@ -204,6 +221,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) static void file_refresh(const bContext *C, ScrArea *sa) { wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); SpaceFile *sfile = CTX_wm_space_file(C); FileSelectParams *params = ED_fileselect_get_params(sfile); struct FSMenu *fsmenu = ED_fsmenu_get(); @@ -217,15 +235,16 @@ static void file_refresh(const bContext *C, ScrArea *sa) } filelist_setdir(sfile->files, params->dir); filelist_setrecursion(sfile->files, params->recursion_level); - filelist_setsorting(sfile->files, params->sort); - filelist_setfilter_options(sfile->files, - (params->flag & FILE_FILTER) != 0, - (params->flag & FILE_HIDE_DOT) != 0, - false, /* TODO hide_parent, should be controllable? */ - params->filter, - params->filter_id, - params->filter_glob, - params->filter_search); + filelist_setsorting(sfile->files, params->sort, params->flag & FILE_SORT_INVERT); + filelist_setfilter_options( + sfile->files, + (params->flag & FILE_FILTER) != 0, + (params->flag & FILE_HIDE_DOT) != 0, + true, /* Just always hide parent, prefer to not add an extra user option for this. */ + params->filter, + params->filter_id, + params->filter_glob, + params->filter_search); /* Update the active indices of bookmarks & co. */ sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir); @@ -254,7 +273,7 @@ static void file_refresh(const bContext *C, ScrArea *sa) else { filelist_cache_previews_set(sfile->files, false); if (sfile->previews_timer) { - WM_event_remove_timer_notifier(wm, CTX_wm_window(C), sfile->previews_timer); + WM_event_remove_timer_notifier(wm, win, sfile->previews_timer); sfile->previews_timer = NULL; } } @@ -269,10 +288,20 @@ static void file_refresh(const bContext *C, ScrArea *sa) /* Might be called with NULL sa, see file_main_region_draw() below. */ if (sa && BKE_area_find_region_type(sa, RGN_TYPE_TOOLS) == NULL) { - /* Create TOOLS/TOOL_PROPS regions. */ + /* Create TOOLS region. */ file_tools_region(sa); - ED_area_initialize(wm, CTX_wm_window(C), sa); + ED_area_initialize(wm, win, sa); + } + if (sa && sfile->op && BKE_area_find_region_type(sa, RGN_TYPE_TOOL_PROPS) == NULL) { + /* Create TOOL_PROPS region. */ + ARegion *region_props = file_tool_props_region(sa); + + if (params->flag & FILE_HIDE_TOOL_PROPS) { + region_props->flag |= RGN_FLAG_HIDDEN; + } + + ED_area_initialize(wm, win, sa); } ED_area_tag_redraw(sa); @@ -406,6 +435,11 @@ static void file_main_region_draw(const bContext *C, ARegion *ar) v2d->keepofs &= ~V2D_LOCKOFS_Y; v2d->keepofs |= V2D_LOCKOFS_X; } + else if (params->display == FILE_VERTICALDISPLAY) { + v2d->scroll = V2D_SCROLL_RIGHT; + v2d->keepofs &= ~V2D_LOCKOFS_Y; + v2d->keepofs |= V2D_LOCKOFS_X; + } else { v2d->scroll = V2D_SCROLL_BOTTOM; v2d->keepofs &= ~V2D_LOCKOFS_X; @@ -439,7 +473,9 @@ static void file_main_region_draw(const bContext *C, ARegion *ar) UI_view2d_view_restore(C); /* scrollers */ - scrollers = UI_view2d_scrollers_calc(v2d, NULL); + rcti view_rect; + ED_fileselect_layout_maskrect(sfile->layout, v2d, &view_rect); + scrollers = UI_view2d_scrollers_calc(v2d, &view_rect); UI_view2d_scrollers_draw(v2d, scrollers); UI_view2d_scrollers_free(scrollers); } @@ -452,6 +488,7 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_select_box); WM_operatortype_append(FILE_OT_select_bookmark); WM_operatortype_append(FILE_OT_highlight); + WM_operatortype_append(FILE_OT_sort_column_ui_context); WM_operatortype_append(FILE_OT_execute); WM_operatortype_append(FILE_OT_cancel); WM_operatortype_append(FILE_OT_parent); @@ -538,7 +575,8 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar) { wmKeyMap *keymap; - UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy); + ED_region_panels_init(wm, ar); + ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y; /* own keymap */ keymap = WM_keymap_ensure(wm->defaultconf, "File Browser", SPACE_FILE, 0); @@ -550,22 +588,18 @@ static void file_ui_region_init(wmWindowManager *wm, ARegion *ar) static void file_ui_region_draw(const bContext *C, ARegion *ar) { - float col[3]; - /* clear */ - UI_GetThemeColor3fv(TH_BACK, col); - GPU_clear_color(col[0], col[1], col[2], 0.0); - GPU_clear(GPU_COLOR_BIT); - - /* scrolling here is just annoying, disable it */ - ar->v2d.cur.ymax = BLI_rctf_size_y(&ar->v2d.cur); - ar->v2d.cur.ymin = 0; - - /* set view2d view matrix for scrolling (without scrollers) */ - UI_view2d_view_ortho(&ar->v2d); + ED_region_panels(C, ar); +} - file_draw_buttons(C, ar); +static void file_execution_region_init(wmWindowManager *wm, ARegion *ar) +{ + ED_region_panels_init(wm, ar); + ar->v2d.keepzoom |= V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y; +} - UI_view2d_view_restore(C); +static void file_execution_region_draw(const bContext *C, ARegion *ar) +{ + ED_region_panels(C, ar); } static void file_ui_region_listener(wmWindow *UNUSED(win), @@ -656,13 +690,21 @@ void ED_spacetype_file(void) /* regions: ui */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); art->regionid = RGN_TYPE_UI; - art->prefsizey = 60; art->keymapflag = ED_KEYMAP_UI; art->listener = file_ui_region_listener; art->init = file_ui_region_init; art->draw = file_ui_region_draw; BLI_addhead(&st->regiontypes, art); + /* regions: execution */ + art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); + art->regionid = RGN_TYPE_EXECUTE; + art->keymapflag = ED_KEYMAP_UI; + art->listener = file_ui_region_listener; + art->init = file_execution_region_init; + art->draw = file_execution_region_draw; + BLI_addhead(&st->regiontypes, art); + /* regions: channels (directories) */ art = MEM_callocN(sizeof(ARegionType), "spacetype file region"); art->regionid = RGN_TYPE_TOOLS; @@ -677,8 +719,8 @@ void ED_spacetype_file(void) /* regions: tool properties */ art = MEM_callocN(sizeof(ARegionType), "spacetype file operator region"); art->regionid = RGN_TYPE_TOOL_PROPS; - art->prefsizex = 0; - art->prefsizey = 360; + art->prefsizex = 240; + art->prefsizey = 60; art->keymapflag = ED_KEYMAP_UI; art->listener = file_tools_region_listener; art->init = file_tools_region_init; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index b624e21937f..329067de545 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -1538,7 +1538,7 @@ void GRAPH_OT_sound_bake(wmOperatorType *ot) FILE_TYPE_FOLDER | FILE_TYPE_SOUND | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE, - WM_FILESEL_FILEPATH, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); RNA_def_float(ot->srna, diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 6478928a6b6..c344b6c8649 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -3520,7 +3520,7 @@ static void initShear_mouseInputMode(TransInfo *t) copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]); } else { - cross_v3_v3v3(dir, t->orient_matrix[t->orient_axis_ortho], t->orient_matrix[t->orient_axis]); + cross_v3_v3v3(dir, t->orient_matrix[t->orient_axis], t->orient_matrix[t->orient_axis_ortho]); } /* Without this, half the gizmo handles move in the opposite direction. */ diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 1be206e921a..604c5bbc083 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -573,7 +573,7 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) if (flags & P_ORIENT_AXIS_ORTHO) { prop = RNA_def_property(ot->srna, "orient_axis_ortho", PROP_ENUM, PROP_NONE); RNA_def_property_ui_text(prop, "Axis Ortho", ""); - RNA_def_property_enum_default(prop, 1); + RNA_def_property_enum_default(prop, 0); RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 613871b1fee..ff1839f997c 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -686,6 +686,7 @@ enum { OB_EMPTY_IMAGE_HIDE_ORTHOGRAPHIC = 1 << 1, OB_EMPTY_IMAGE_HIDE_BACK = 1 << 2, OB_EMPTY_IMAGE_HIDE_FRONT = 1 << 3, + OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED = 1 << 4, }; /** #Object.empty_image_flag */ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 5f5bd3142c4..5e96759bc90 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2002,6 +2002,8 @@ extern const char *RE_engine_id_CYCLES; (((workspace)->object_mode & OD_MODE_EDIT) ? OBACT(_view_layer) : NULL) #define OBEDIT_FROM_OBACT(ob) ((ob) ? (((ob)->mode & OB_MODE_EDIT) ? ob : NULL) : NULL) #define OBPOSE_FROM_OBACT(ob) ((ob) ? (((ob)->mode & OB_MODE_POSE) ? ob : NULL) : NULL) +#define OBWEIGHTPAINT_FROM_OBACT(ob) \ + ((ob) ? (((ob)->mode & OB_MODE_WEIGHT_PAINT) ? ob : NULL) : NULL) #define OBEDIT_FROM_VIEW_LAYER(view_layer) OBEDIT_FROM_OBACT(OBACT(view_layer)) #define V3D_CAMERA_LOCAL(v3d) ((!(v3d)->scenelock && (v3d)->camera) ? (v3d)->camera : NULL) diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 1b4e4dc23ee..2fc42e904c2 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -677,8 +677,11 @@ typedef struct FileSelectParams { /** Display mode flag. */ short display; short display_previous; + /** Details toggles (file size, creation date, etc.) */ + char details_flags; + /* The type of file action (opening or saving) */ + char action_type; /* eFileSel_Action */ /** Filter when (flags & FILE_FILTER) is true. */ - char _pad2[2]; int filter; /** Max number of levels in dirtree to show at once, 0 to disable recursion. */ @@ -736,8 +739,8 @@ typedef struct SpaceFile { /* FileSelectParams.display */ enum eFileDisplayType { FILE_DEFAULTDISPLAY = 0, - FILE_SHORTDISPLAY = 1, - FILE_LONGDISPLAY = 2, + FILE_VERTICALDISPLAY = 1, + FILE_HORIZONTALDISPLAY = 2, FILE_IMGDISPLAY = 3, }; @@ -750,6 +753,12 @@ enum eFileSortType { FILE_SORT_SIZE = 4, }; +/* FileSelectParams.details_flags */ +enum eFileDetails { + FILE_DETAILS_SIZE = (1 << 0), + FILE_DETAILS_DATETIME = (1 << 1), +}; + /* these values need to be hardcoded in structs, dna does not recognize defines */ /* also defined in BKE */ #define FILE_MAXDIR 768 @@ -787,6 +796,8 @@ typedef enum eFileSel_Params_Flag { FILE_FILTER = (1 << 8), FILE_PARAMS_FLAG_UNUSED_9 = (1 << 9), /* cleared */ FILE_GROUP_INSTANCE = (1 << 10), + FILE_SORT_INVERT = (1 << 11), + FILE_HIDE_TOOL_PROPS = (1 << 12) } eFileSel_Params_Flag; /* sfile->params->rename_flag */ @@ -824,6 +835,8 @@ typedef enum eFileSel_File_Types { FILE_TYPE_OPERATOR = (1 << 14), FILE_TYPE_APPLICATIONBUNDLE = (1 << 15), FILE_TYPE_ALEMBIC = (1 << 16), + /** For all kinds of recognized import/export formats. No need for specialized types. */ + FILE_TYPE_OBJECT_IO = (1 << 17), /** An FS directory (i.e. S_ISDIR on its path is true). */ FILE_TYPE_DIR = (1 << 30), @@ -882,8 +895,7 @@ typedef struct FileDirEntryRevision { int64_t time; /* Temp caching of UI-generated strings... */ char size_str[16]; - char time_str[8]; - char date_str[16]; + char datetime_str[16 + 8]; } FileDirEntryRevision; /* Container for a variant, only relevant in asset context. diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 3c0fd282b17..c8a0d543b70 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -2821,6 +2821,14 @@ static void rna_def_object(BlenderRNA *brna) prop, "Display in Orthographic Mode", "Display image in orthographic mode"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + prop = RNA_def_property(srna, "show_empty_image_only_axis_aligned", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna( + prop, NULL, "empty_image_visibility_flag", OB_EMPTY_IMAGE_HIDE_NON_AXIS_ALIGNED); + RNA_def_property_ui_text(prop, + "Display Only Axis Aligned", + "Only display the image when it is aligned with the view axis"); + RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); + prop = RNA_def_property(srna, "use_empty_image_alpha", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "empty_image_flag", OB_EMPTY_IMAGE_USE_ALPHA_BLEND); RNA_def_property_ui_text( diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index b0226b09b88..ca857fb7be8 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -420,19 +420,19 @@ const EnumPropertyItem rna_enum_file_sort_items[] = { {FILE_SORT_ALPHA, "FILE_SORT_ALPHA", ICON_SORTALPHA, - "Sort alphabetically", + "Name", "Sort the file list alphabetically"}, {FILE_SORT_EXTENSION, "FILE_SORT_EXTENSION", ICON_SORTBYEXT, - "Sort by extension", + "Extension", "Sort the file list by extension/type"}, {FILE_SORT_TIME, "FILE_SORT_TIME", ICON_SORTTIME, - "Sort by time", + "Modified Date", "Sort files by modification time"}, - {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Sort by size", "Sort files by size"}, + {FILE_SORT_SIZE, "FILE_SORT_SIZE", ICON_SORTSIZE, "Size", "Sort files by size"}, {0, NULL, 0, NULL, NULL}, }; @@ -2142,6 +2142,18 @@ static void rna_SpaceClipEditor_view_type_update(Main *UNUSED(bmain), /* File browser. */ +int rna_FileSelectParams_filename_editable(struct PointerRNA *ptr, const char **r_info) +{ + FileSelectParams *params = ptr->data; + + if (params && (params->flag & FILE_DIRSEL_ONLY)) { + *r_info = "Only directories can be chosen for the current operation."; + return 0; + } + + return params ? PROP_EDITABLE : 0; +} + static bool rna_FileSelectParams_use_lib_get(PointerRNA *ptr) { FileSelectParams *params = ptr->data; @@ -5133,25 +5145,25 @@ static void rna_def_fileselect_params(BlenderRNA *brna) PropertyRNA *prop; static const EnumPropertyItem file_display_items[] = { - {FILE_SHORTDISPLAY, - "LIST_SHORT", - ICON_SHORTDISPLAY, - "Short List", - "Display files as short list"}, - {FILE_LONGDISPLAY, - "LIST_LONG", + {FILE_VERTICALDISPLAY, + "LIST_VERTICAL", ICON_LONGDISPLAY, - "Long List", - "Display files as a detailed list"}, + "Vertical List", + "Display files as a vertical list"}, + {FILE_HORIZONTALDISPLAY, + "LIST_HORIZONTAL", + ICON_SHORTDISPLAY, + "Horizontal List", + "Display files as a horizontal list"}, {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem display_size_items[] = { - {32, "TINY", 0, "Tiny", ""}, - {64, "SMALL", 0, "Small", ""}, + {64, "TINY", 0, "Tiny", ""}, + {96, "SMALL", 0, "Small", ""}, {128, "NORMAL", 0, "Regular", ""}, - {256, "LARGE", 0, "Large", ""}, + {192, "LARGE", 0, "Large", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -5267,7 +5279,10 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Title", "Title for the file browser"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_DIRPATH); + /* Use BYTESTRING rather than DIRPATH as subtype so UI code doesn't add OT_directory_browse + * button when displaying this prop in the file browser (it would just open a file browser). That + * should be the only effective difference between the two. */ + prop = RNA_def_property(srna, "directory", PROP_STRING, PROP_BYTESTRING); RNA_def_property_string_sdna(prop, NULL, "dir"); RNA_def_property_ui_text(prop, "Directory", "Directory displayed in the file browser"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); @@ -5275,6 +5290,7 @@ static void rna_def_fileselect_params(BlenderRNA *brna) prop = RNA_def_property(srna, "filename", PROP_STRING, PROP_FILENAME); RNA_def_property_string_sdna(prop, NULL, "file"); RNA_def_property_ui_text(prop, "File Name", "Active file in the file browser"); + RNA_def_property_editable_func(prop, "rna_FileSelectParams_filename_editable"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); prop = RNA_def_property(srna, "use_library_browsing", PROP_BOOLEAN, PROP_NONE); @@ -5295,6 +5311,19 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Recursion", "Numbers of dirtree levels to show simultaneously"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + prop = RNA_def_property(srna, "show_details_size", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_SIZE); + RNA_def_property_ui_text(prop, "File Size", "Draw a column listing the size of each file"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + + prop = RNA_def_property(srna, "show_details_datetime", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "details_flags", FILE_DETAILS_DATETIME); + RNA_def_property_ui_text( + prop, + "File Modification Date", + "Draw a column listing the date and time of modification for each file"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + prop = RNA_def_property(srna, "use_filter", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_FILTER); RNA_def_property_ui_text(prop, "Filter Files", "Enable filtering of files"); @@ -5311,6 +5340,12 @@ static void rna_def_fileselect_params(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sort", ""); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + prop = RNA_def_property(srna, "use_sort_invert", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", FILE_SORT_INVERT); + RNA_def_property_ui_text( + prop, "Reverse Sorting", "Sort items descending, from highest value to lowest"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); + prop = RNA_def_property(srna, "use_filter_image", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filter", FILE_TYPE_IMAGE); RNA_def_property_ui_text(prop, "Filter Images", "Show image files"); diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 2ab08c82b63..2015356d071 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -835,7 +835,7 @@ static void rna_def_texture_clouds(BlenderRNA *brna) prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "noisedepth"); RNA_def_property_range(prop, 0, 30); - RNA_def_property_ui_range(prop, 0, 24, 0, 2); + RNA_def_property_ui_range(prop, 0, 24, 1, 2); RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the cloud calculation"); RNA_def_property_update(prop, 0, "rna_Texture_nodes_update"); @@ -974,7 +974,7 @@ static void rna_def_texture_marble(BlenderRNA *brna) prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "noisedepth"); RNA_def_property_range(prop, 0, 30); - RNA_def_property_ui_range(prop, 0, 24, 0, 2); + RNA_def_property_ui_range(prop, 0, 24, 1, 2); RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the cloud calculation"); RNA_def_property_update(prop, 0, "rna_Texture_update"); @@ -1028,7 +1028,7 @@ static void rna_def_texture_magic(BlenderRNA *brna) prop = RNA_def_property(srna, "noise_depth", PROP_INT, PROP_NONE); RNA_def_property_int_sdna(prop, NULL, "noisedepth"); RNA_def_property_range(prop, 0, 30); - RNA_def_property_ui_range(prop, 0, 24, 0, 2); + RNA_def_property_ui_range(prop, 0, 24, 1, 2); RNA_def_property_ui_text(prop, "Noise Depth", "Depth of the noise"); RNA_def_property_update(prop, 0, "rna_Texture_update"); } diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index cdcc28a55bb..8d18488d234 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -148,6 +148,10 @@ if(WITH_MOD_OCEANSIM) add_definitions(-DWITH_OCEANSIM) endif() +if(WITH_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() + if(WITH_BULLET) list(APPEND LIB extern_bullet diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index c64d9be1158..dd7c001931c 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -168,6 +168,10 @@ static Mesh *multires_as_ccg(MultiresModifierData *mmd, static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { Mesh *result = mesh; +#if !defined(WITH_OPENSUBDIV) + modifier_setError(md, "Disabled, built without OpenSubdiv"); + return result; +#endif MultiresModifierData *mmd = (MultiresModifierData *)md; SubdivSettings subdiv_settings; BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 0b1249e263c..08a884fa879 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -208,6 +208,10 @@ static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd) static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh) { Mesh *result = mesh; +#if !defined(WITH_OPENSUBDIV) + modifier_setError(md, "Disabled, built without OpenSubdiv"); + return result; +#endif SubsurfModifierData *smd = (SubsurfModifierData *)md; SubdivSettings subdiv_settings; subdiv_settings_init(&subdiv_settings, smd); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index fc945562c98..a5f71e92438 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -231,6 +231,10 @@ if(WITH_OPENAL) add_definitions(-DWITH_OPENAL) endif() +if(WITH_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() + if(WITH_SDL) list(APPEND INC_SYS ${SDL_INCLUDE_DIR} diff --git a/source/blender/python/intern/bpy_app_build_options.c b/source/blender/python/intern/bpy_app_build_options.c index a841e974e85..afb2f6b3636 100644 --- a/source/blender/python/intern/bpy_app_build_options.c +++ b/source/blender/python/intern/bpy_app_build_options.c @@ -46,6 +46,7 @@ static PyStructSequence_Field app_builtopts_info_fields[] = { {(char *)"audaspace", NULL}, {(char *)"international", NULL}, {(char *)"openal", NULL}, + {(char *)"opensubdiv", NULL}, {(char *)"sdl", NULL}, {(char *)"sdl_dynload", NULL}, {(char *)"jack", NULL}, @@ -190,6 +191,12 @@ static PyObject *make_builtopts_info(void) SetObjIncref(Py_False); #endif +#ifdef WITH_OPENSUBDIV + SetObjIncref(Py_True); +#else + SetObjIncref(Py_False); +#endif + #ifdef WITH_SDL SetObjIncref(Py_True); #else diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 13be8701c27..c7b18adf9b1 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -159,7 +159,7 @@ enum { WM_WINDOW_USERPREFS, WM_WINDOW_DRIVERS, WM_WINDOW_INFO, - // WM_WINDOW_FILESEL // UNUSED + WM_WINDOW_FILESEL, }; struct wmWindow *WM_window_open(struct bContext *C, const struct rcti *rect); @@ -493,6 +493,8 @@ bool WM_operator_properties_checker_interval_test(const struct CheckerIntervalPa #define WM_FILESEL_FILENAME (1 << 2) #define WM_FILESEL_FILEPATH (1 << 3) #define WM_FILESEL_FILES (1 << 4) +/* Show the properties sidebar by default. */ +#define WM_FILESEL_SHOW_PROPS (1 << 5) /* operator as a python command (resultuing string must be freed) */ char *WM_operator_pystring_ex(struct bContext *C, diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 51191b45439..9fe53cb3af0 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2339,45 +2339,31 @@ static int wm_handler_fileselect_do(bContext *C, switch (val) { case EVT_FILESELECT_FULL_OPEN: { - ScrArea *sa; + wmWindow *win = CTX_wm_window(C); + const int sizex = 1020 * UI_DPI_FAC; + const int sizey = 600 * UI_DPI_FAC; - /* sa can be null when window A is active, but mouse is over window B - * in this case, open file select in original window A. Also don't - * use global areas. */ - if (handler->context.area == NULL || ED_area_is_global(handler->context.area)) { - bScreen *screen = CTX_wm_screen(C); - sa = (ScrArea *)screen->areabase.first; - } - else { - sa = handler->context.area; - } + if (WM_window_open_temp( + C, win->sizex / 2, win->sizey / 2, sizex, sizey, WM_WINDOW_FILESEL) != NULL) { + ScrArea *area = CTX_wm_area(C); + ARegion *region_header = BKE_area_find_region_type(area, RGN_TYPE_HEADER); - if (sa->full) { - /* ensure the first area becomes the file browser, because the second one is the small - * top (info-)area which might be too small (in fullscreens we have max two areas) */ - if (sa->prev) { - sa = sa->prev; - } - ED_area_newspace(C, sa, SPACE_FILE, true); /* 'sa' is modified in-place */ - /* we already had a fullscreen here -> mark new space as a stacked fullscreen */ - sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE); - } - else if (sa->spacetype == SPACE_FILE) { - sa = ED_screen_state_toggle(C, CTX_wm_window(C), sa, SCREENMAXIMIZED); - } - else { - sa = ED_screen_full_newspace(C, sa, SPACE_FILE); /* sets context */ - } + BLI_assert(area->spacetype == SPACE_FILE); - /* note, getting the 'sa' back from the context causes a nasty bug where the newly created - * 'sa' != CTX_wm_area(C). removed the line below and set 'sa' in the 'if' above */ - /* sa = CTX_wm_area(C); */ + region_header->flag |= RGN_FLAG_HIDDEN; + /* Header on bottom, AZone triangle to toggle header looks misplaced at the top */ + region_header->alignment = RGN_ALIGN_BOTTOM; - /* settings for filebrowser, sfile is not operator owner but sends events */ - sfile = (SpaceFile *)sa->spacedata.first; - sfile->op = handler->op; + /* settings for filebrowser, sfile is not operator owner but sends events */ + sfile = (SpaceFile *)area->spacedata.first; + sfile->op = handler->op; - ED_fileselect_set_params(sfile); + ED_fileselect_set_params(sfile); + } + else { + BKE_report(&wm->reports, RPT_ERROR, "Failed to open window!"); + return OPERATOR_CANCELLED; + } action = WM_HANDLER_BREAK; break; @@ -2390,14 +2376,27 @@ static int wm_handler_fileselect_do(bContext *C, BLI_remlink(handlers, handler); if (val != EVT_FILESELECT_EXTERNAL_CANCEL) { - ScrArea *sa = CTX_wm_area(C); + for (wmWindow *win = wm->windows.first; win; win = win->next) { + if (WM_window_is_temp_screen(win)) { + bScreen *screen = WM_window_get_active_screen(win); + ScrArea *file_sa = screen->areabase.first; - if (sa->full) { - ED_screen_full_prevspace(C, sa); - } - /* user may have left fullscreen */ - else { - ED_area_prevspace(C, sa); + BLI_assert(file_sa->spacetype == SPACE_FILE); + + if (BLI_listbase_is_single(&file_sa->spacedata)) { + wmWindow *ctx_win = CTX_wm_window(C); + wm_window_close(C, wm, win); + CTX_wm_window_set(C, ctx_win); // wm_window_close() NULLs. + } + else if (file_sa->full) { + ED_screen_full_prevspace(C, file_sa); + } + else { + ED_area_prevspace(C, file_sa); + } + + break; + } } } diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index ae704142d5a..af841f20620 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -1205,6 +1205,8 @@ static ImBuf *blend_file_thumb(const bContext *C, /* will be scaled down, but gives some nice oversampling */ ImBuf *ibuf; BlendThumbnail *thumb; + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *windrawable_old = wm->windrawable; char err_out[256] = "unknown"; /* screen if no camera found */ @@ -1238,6 +1240,9 @@ static ImBuf *blend_file_thumb(const bContext *C, /* gets scaled to BLEN_THUMB_SIZE */ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + /* Offscreen drawing requires a drawable window context. */ + wm_window_make_drawable(wm, CTX_wm_window(C)); + if (scene->camera) { ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, @@ -1270,6 +1275,14 @@ static ImBuf *blend_file_thumb(const bContext *C, err_out); } + /* Reset to old drawable. */ + if (windrawable_old) { + wm_window_make_drawable(wm, windrawable_old); + } + else { + wm_window_clear_drawable(wm); + } + if (ibuf) { float aspect = (scene->r.xsch * scene->r.xasp) / (scene->r.ysch * scene->r.yasp); @@ -2322,7 +2335,7 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op) void WM_OT_open_mainfile(wmOperatorType *ot) { - ot->name = "Open Blender File"; + ot->name = "Open"; ot->idname = "WM_OT_open_mainfile"; ot->description = "Open a Blender file"; @@ -2504,7 +2517,7 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) FILE_BLENDER, FILE_OPENFILE, WM_FILESEL_FILEPATH, - FILE_LONGDISPLAY, + FILE_HORIZONTALDISPLAY, FILE_SORT_TIME); } @@ -2638,7 +2651,7 @@ void WM_OT_save_as_mainfile(wmOperatorType *ot) { PropertyRNA *prop; - ot->name = "Save As Blender File"; + ot->name = "Save As"; ot->idname = "WM_OT_save_as_mainfile"; ot->description = "Save the current file in the desired location"; diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 5a6606984ba..2cd2cf0636a 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -561,7 +561,7 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link) void WM_OT_link(wmOperatorType *ot) { - ot->name = "Link from Library"; + ot->name = "Link"; ot->idname = "WM_OT_link"; ot->description = "Link from a Library .blend file"; @@ -585,7 +585,7 @@ void WM_OT_link(wmOperatorType *ot) void WM_OT_append(wmOperatorType *ot) { - ot->name = "Append from Library"; + ot->name = "Append"; ot->idname = "WM_OT_append"; ot->description = "Append from a Library .blend file"; diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index fcb55d3f801..663e4adf06b 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -65,19 +65,27 @@ void WM_operator_properties_filesel(wmOperatorType *ot, 0, "Default", "Automatically determine display type for files"}, - {FILE_SHORTDISPLAY, - "LIST_SHORT", - ICON_SHORTDISPLAY, + {FILE_VERTICALDISPLAY, + "LIST_VERTICAL", + ICON_SHORTDISPLAY, /* Name of deprecated short list */ "Short List", "Display files as short list"}, - {FILE_LONGDISPLAY, - "LIST_LONG", - ICON_LONGDISPLAY, + {FILE_HORIZONTALDISPLAY, + "LIST_HORIZONTAL", + ICON_LONGDISPLAY, /* Name of deprecated long list */ "Long List", "Display files as a detailed list"}, {FILE_IMGDISPLAY, "THUMBNAIL", ICON_IMGDISPLAY, "Thumbnails", "Display files as thumbnails"}, {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem file_action_types[] = { + {FILE_OPENFILE, + "OPENFILE", + 0, + "Open", + "Use the file browser for opening files or a directory"}, + {FILE_SAVE, "SAVE", 0, "Save", "Use the file browser for saving a file"}, + }; if (flag & WM_FILESEL_FILEPATH) { RNA_def_string_file_path(ot->srna, "filepath", NULL, FILE_MAX, "File Path", "Path to file"); @@ -99,6 +107,15 @@ void WM_operator_properties_filesel(wmOperatorType *ot, RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } + if ((flag & WM_FILESEL_SHOW_PROPS) == 0) { + prop = RNA_def_boolean(ot->srna, + "hide_props_region", + true, + "Hide Operator Properties", + "Collapse the region displaying the operator settings"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + } + if (action == FILE_SAVE) { /* note, this is only used to check if we should highlight the filename area red when the * filepath is an existing file. */ @@ -186,6 +203,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot, prop = RNA_def_enum( ot->srna, "sort_method", rna_enum_file_sort_items, sort, "File sorting mode", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_enum(ot->srna, "action_type", file_action_types, action, "Action Type", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } static void wm_operator_properties_select_action_ex(wmOperatorType *ot, diff --git a/source/blender/windowmanager/intern/wm_splash_screen.c b/source/blender/windowmanager/intern/wm_splash_screen.c index 8629997030f..d3f7661a008 100644 --- a/source/blender/windowmanager/intern/wm_splash_screen.c +++ b/source/blender/windowmanager/intern/wm_splash_screen.c @@ -113,31 +113,37 @@ static void wm_block_splash_add_label(uiBlock *block, const char *label, int x, static void wm_block_splash_add_labels(uiBlock *block, int x, int y) { /* Version number. */ - const char *version_suffix = NULL; + const char *version_cycle = NULL; bool show_build_info = true; if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) { - version_suffix = " Alpha"; + version_cycle = " Alpha"; } else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) { - version_suffix = " Beta"; + version_cycle = " Beta"; } else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) { - version_suffix = " Release Candidate"; + version_cycle = " Release Candidate"; show_build_info = false; } else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) { - version_suffix = STRINGIFY(BLENDER_VERSION_CHAR); + version_cycle = STRINGIFY(BLENDER_VERSION_CHAR); show_build_info = false; } + const char *version_cycle_number = ""; + if (strlen(STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER))) { + version_cycle_number = " " STRINGIFY(BLENDER_VERSION_CYCLE_NUMBER); + } + char version_buf[256] = "\0"; BLI_snprintf(version_buf, sizeof(version_buf), - "v %d.%d%s", + "v %d.%d%s%s", BLENDER_VERSION / 100, BLENDER_VERSION % 100, - version_suffix); + version_cycle, + version_cycle_number); wm_block_splash_add_label(block, version_buf, x, &y); diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 47491813f70..00ed203c208 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -807,6 +807,7 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i ScrArea *sa; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + eSpace_Type space_type = SPACE_EMPTY; const char *title; /* convert to native OS window coordinates */ @@ -888,17 +889,24 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i CTX_wm_area_set(C, sa); if (type == WM_WINDOW_RENDER) { - ED_area_newspace(C, sa, SPACE_IMAGE, false); + space_type = SPACE_IMAGE; } else if (type == WM_WINDOW_DRIVERS) { - ED_area_newspace(C, sa, SPACE_GRAPH, false); + space_type = SPACE_GRAPH; + } + else if (type == WM_WINDOW_USERPREFS) { + space_type = SPACE_USERPREF; + } + else if (type == WM_WINDOW_FILESEL) { + space_type = SPACE_FILE; } else if (type == WM_WINDOW_INFO) { ED_area_newspace(C, sa, SPACE_INFO, false); } else { - ED_area_newspace(C, sa, SPACE_USERPREF, false); + BLI_assert(false); } + ED_area_newspace(C, sa, space_type, false); ED_screen_change(C, screen); ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */ |