work in progress, resource previews
|
@ -1746,6 +1746,10 @@ Error Image::_decompress_bc() {
|
|||
return OK;
|
||||
}
|
||||
|
||||
bool Image::is_compressed() const {
|
||||
return format>=FORMAT_BC1;
|
||||
}
|
||||
|
||||
|
||||
Image Image::decompressed() const {
|
||||
|
||||
|
@ -1998,7 +2002,7 @@ void Image::blit_rect(const Image& p_src, const Rect2& p_src_rect,const Point2&
|
|||
}
|
||||
|
||||
|
||||
Image (*Image::_png_mem_loader_func)(const uint8_t*)=NULL;
|
||||
Image (*Image::_png_mem_loader_func)(const uint8_t*,int)=NULL;
|
||||
void (*Image::_image_compress_bc_func)(Image *)=NULL;
|
||||
void (*Image::_image_compress_pvrtc2_func)(Image *)=NULL;
|
||||
void (*Image::_image_compress_pvrtc4_func)(Image *)=NULL;
|
||||
|
@ -2167,7 +2171,7 @@ void Image::fix_alpha_edges() {
|
|||
|
||||
}
|
||||
|
||||
Image::Image(const uint8_t* p_png) {
|
||||
Image::Image(const uint8_t* p_png,int p_len) {
|
||||
|
||||
width=0;
|
||||
height=0;
|
||||
|
@ -2175,7 +2179,7 @@ Image::Image(const uint8_t* p_png) {
|
|||
format=FORMAT_GRAYSCALE;
|
||||
|
||||
if (_png_mem_loader_func) {
|
||||
*this = _png_mem_loader_func(p_png);
|
||||
*this = _png_mem_loader_func(p_png,p_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ public:
|
|||
/* INTERPOLATE GAUSS */
|
||||
};
|
||||
|
||||
static Image (*_png_mem_loader_func)(const uint8_t* p_png);
|
||||
static Image (*_png_mem_loader_func)(const uint8_t* p_png,int p_size);
|
||||
static void (*_image_compress_bc_func)(Image *);
|
||||
static void (*_image_compress_pvrtc2_func)(Image *);
|
||||
static void (*_image_compress_pvrtc4_func)(Image *);
|
||||
|
@ -335,6 +335,7 @@ public:
|
|||
Image compressed(int p_mode); /* from the Image::CompressMode enum */
|
||||
Error decompress();
|
||||
Image decompressed() const;
|
||||
bool is_compressed() const;
|
||||
|
||||
void fix_alpha_edges();
|
||||
void premultiply_alpha();
|
||||
|
@ -349,7 +350,7 @@ public:
|
|||
Image get_rect(const Rect2& p_area) const;
|
||||
|
||||
static void set_compress_bc_func(void (*p_compress_func)(Image *));
|
||||
Image(const uint8_t* p_mem_png);
|
||||
Image(const uint8_t* p_mem_png, int p_len=-1);
|
||||
Image(const char **p_xpm);
|
||||
~Image();
|
||||
|
||||
|
|
|
@ -74,6 +74,14 @@ bool FileAccessMemory::file_exists(const String& p_name) {
|
|||
}
|
||||
|
||||
|
||||
Error FileAccessMemory::open_custom(const uint8_t* p_data, int p_len) {
|
||||
|
||||
data=(uint8_t*)p_data;
|
||||
length=p_len;
|
||||
pos=0;
|
||||
return OK;
|
||||
}
|
||||
|
||||
Error FileAccessMemory::_open(const String& p_path, int p_mode_flags) {
|
||||
|
||||
ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
|
||||
|
|
|
@ -44,6 +44,7 @@ public:
|
|||
static void register_file(String p_name, Vector<uint8_t> p_data);
|
||||
static void cleanup();
|
||||
|
||||
virtual Error open_custom(const uint8_t* p_data, int p_len); ///< open a file
|
||||
virtual Error _open(const String& p_path, int p_mode_flags); ///< open a file
|
||||
virtual void close(); ///< close a file
|
||||
virtual bool is_open() const; ///< true when file is open
|
||||
|
|
|
@ -1351,7 +1351,7 @@ Error Object::connect(const StringName& p_signal, Object *p_to_object, const Str
|
|||
if (!s) {
|
||||
bool signal_is_valid = ObjectTypeDB::has_signal(get_type_name(),p_signal);
|
||||
if (!signal_is_valid) {
|
||||
ERR_EXPLAIN("Attempt to connect to nonexistent signal: "+p_signal);
|
||||
ERR_EXPLAIN("Attempt to connect nonexistent signal '"+p_signal+"' to method '"+p_to_method+"'");
|
||||
ERR_FAIL_COND_V(!signal_is_valid,ERR_INVALID_PARAMETER);
|
||||
}
|
||||
signal_map[p_signal]=Signal();
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#include "print_string.h"
|
||||
#include "os/os.h"
|
||||
|
||||
|
||||
|
||||
void ImageLoaderPNG::_read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length) {
|
||||
|
||||
FileAccess *f = (FileAccess*)png_get_io_ptr(png_ptr);
|
||||
|
@ -253,6 +255,7 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const
|
|||
struct PNGReadStatus {
|
||||
|
||||
int offset;
|
||||
int size;
|
||||
const unsigned char *image;
|
||||
};
|
||||
|
||||
|
@ -261,17 +264,26 @@ static void user_read_data(png_structp png_ptr,png_bytep data, png_size_t p_leng
|
|||
PNGReadStatus *rstatus;
|
||||
rstatus=(PNGReadStatus*)png_get_io_ptr(png_ptr);
|
||||
|
||||
memcpy(data,&rstatus->image[rstatus->offset],p_length);
|
||||
rstatus->offset+=p_length;
|
||||
int to_read=p_length;
|
||||
if (rstatus->size>=0) {
|
||||
to_read = MIN( p_length, rstatus->size - rstatus->offset);
|
||||
}
|
||||
memcpy(data,&rstatus->image[rstatus->offset],to_read);
|
||||
rstatus->offset+=to_read;
|
||||
|
||||
if (to_read<p_length) {
|
||||
memset(&data[to_read],0,p_length-to_read);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static Image _load_mem_png(const uint8_t* p_png) {
|
||||
static Image _load_mem_png(const uint8_t* p_png,int p_size) {
|
||||
|
||||
|
||||
PNGReadStatus prs;
|
||||
prs.image=p_png;
|
||||
prs.offset=0;
|
||||
prs.size=p_size;
|
||||
|
||||
Image img;
|
||||
Error err = ImageLoaderPNG::_load_image(&prs,user_read_data,&img);
|
||||
|
@ -283,9 +295,10 @@ static Image _load_mem_png(const uint8_t* p_png) {
|
|||
|
||||
static Image _lossless_unpack_png(const DVector<uint8_t>& p_data) {
|
||||
|
||||
int len = p_data.size();
|
||||
DVector<uint8_t>::Read r = p_data.read();
|
||||
ERR_FAIL_COND_V(r[0]!='P' || r[1]!='N' || r[2]!='G' || r[3]!=' ',Image());
|
||||
return _load_mem_png(&r[4]);
|
||||
return _load_mem_png(&r[4],len-4);
|
||||
|
||||
}
|
||||
|
||||
|
@ -424,6 +437,7 @@ static DVector<uint8_t> _lossless_pack_png(const Image& p_image) {
|
|||
|
||||
ImageLoaderPNG::ImageLoaderPNG() {
|
||||
|
||||
|
||||
Image::_png_mem_loader_func=_load_mem_png;
|
||||
Image::lossless_unpacker=_lossless_unpack_png;
|
||||
Image::lossless_packer=_lossless_pack_png;
|
||||
|
|
|
@ -40,7 +40,10 @@ class ImageLoaderPNG : public ImageFormatLoader {
|
|||
static void _read_png_data(png_structp png_ptr,png_bytep data, png_size_t p_length);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
static Error _load_image(void *rf_up,png_rw_ptr p_func,Image *p_image);
|
||||
virtual Error load_image(Image *p_image,FileAccess *f);
|
||||
virtual void get_recognized_extensions(List<String> *p_extensions) const;
|
||||
|
|
|
@ -692,7 +692,6 @@ void make_default_theme() {
|
|||
// FileDialog
|
||||
|
||||
t->set_icon("folder","FileDialog",make_icon(icon_folder_png));
|
||||
|
||||
t->set_color("files_disabled","FileDialog",Color(0,0,0,0.7));
|
||||
|
||||
|
||||
|
|
874
tools/editor/editor_file_dialog.cpp
Normal file
|
@ -0,0 +1,874 @@
|
|||
#include "editor_file_dialog.h"
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/gui/center_container.h"
|
||||
#include "print_string.h"
|
||||
#include "os/keyboard.h"
|
||||
#include "editor_resource_preview.h"
|
||||
|
||||
|
||||
EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func=NULL;
|
||||
EditorFileDialog::GetIconFunc EditorFileDialog::get_large_icon_func=NULL;
|
||||
|
||||
EditorFileDialog::RegisterFunc EditorFileDialog::register_func=NULL;
|
||||
EditorFileDialog::RegisterFunc EditorFileDialog::unregister_func=NULL;
|
||||
|
||||
|
||||
VBoxContainer *EditorFileDialog::get_vbox() {
|
||||
return vbox;
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_notification(int p_what) {
|
||||
if (p_what==NOTIFICATION_PROCESS) {
|
||||
|
||||
if (preview_waiting) {
|
||||
preview_wheel_timeout-=get_process_delta_time();
|
||||
if (preview_wheel_timeout<=0) {
|
||||
preview_wheel_index++;
|
||||
if (preview_wheel_index>=8)
|
||||
preview_wheel_index=0;
|
||||
Ref<Texture> frame = get_icon("WaitPreview"+itos(preview_wheel_index+1),"EditorIcons");
|
||||
preview->set_texture(frame);
|
||||
preview_wheel_timeout=0.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p_what==NOTIFICATION_DRAW) {
|
||||
|
||||
//RID ci = get_canvas_item();
|
||||
//get_stylebox("panel","PopupMenu")->draw(ci,Rect2(Point2(),get_size()));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileDialog::set_enable_multiple_selection(bool p_enable) {
|
||||
|
||||
tree->set_select_mode(p_enable?Tree::SELECT_MULTI : Tree::SELECT_SINGLE);
|
||||
};
|
||||
|
||||
Vector<String> EditorFileDialog::get_selected_files() const {
|
||||
|
||||
Vector<String> list;
|
||||
|
||||
TreeItem* item = tree->get_root();
|
||||
while ( (item = tree->get_next_selected(item)) ) {
|
||||
|
||||
list.push_back(dir_access->get_current_dir().plus_file(item->get_text(0)));
|
||||
};
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
void EditorFileDialog::update_dir() {
|
||||
|
||||
dir->set_text(dir_access->get_current_dir());
|
||||
}
|
||||
|
||||
void EditorFileDialog::_dir_entered(String p_dir) {
|
||||
|
||||
|
||||
dir_access->change_dir(p_dir);
|
||||
file->set_text("");
|
||||
invalidate();
|
||||
update_dir();
|
||||
}
|
||||
|
||||
void EditorFileDialog::_file_entered(const String& p_file) {
|
||||
|
||||
_action_pressed();
|
||||
}
|
||||
|
||||
void EditorFileDialog::_save_confirm_pressed() {
|
||||
String f=dir_access->get_current_dir().plus_file(file->get_text());
|
||||
emit_signal("file_selected",f);
|
||||
hide();
|
||||
}
|
||||
|
||||
void EditorFileDialog::_post_popup() {
|
||||
|
||||
ConfirmationDialog::_post_popup();
|
||||
if (invalidated) {
|
||||
update_file_list();
|
||||
invalidated=false;
|
||||
}
|
||||
if (mode==MODE_SAVE_FILE)
|
||||
file->grab_focus();
|
||||
else
|
||||
tree->grab_focus();
|
||||
|
||||
if (is_visible() && get_current_file()!="")
|
||||
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) {
|
||||
|
||||
set_process(false);
|
||||
preview_waiting=false;
|
||||
|
||||
if (p_preview.is_valid() && get_current_path()==p_path) {
|
||||
|
||||
preview->set_texture(p_preview);
|
||||
preview_vb->show();
|
||||
|
||||
} else {
|
||||
preview_vb->hide();
|
||||
preview->set_texture(Ref<Texture>());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_request_single_thumbnail(const String& p_path) {
|
||||
|
||||
EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path);
|
||||
print_line("want file "+p_path);
|
||||
set_process(true);
|
||||
preview_waiting=true;
|
||||
preview_wheel_timeout=0;
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_action_pressed() {
|
||||
|
||||
if (mode==MODE_OPEN_FILES) {
|
||||
|
||||
TreeItem *ti=tree->get_next_selected(NULL);
|
||||
String fbase=dir_access->get_current_dir();
|
||||
|
||||
DVector<String> files;
|
||||
while(ti) {
|
||||
|
||||
files.push_back( fbase.plus_file(ti->get_text(0)) );
|
||||
ti=tree->get_next_selected(ti);
|
||||
}
|
||||
|
||||
if (files.size()) {
|
||||
emit_signal("files_selected",files);
|
||||
hide();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String f=dir_access->get_current_dir().plus_file(file->get_text());
|
||||
|
||||
if (mode==MODE_OPEN_FILE && dir_access->file_exists(f)) {
|
||||
emit_signal("file_selected",f);
|
||||
hide();
|
||||
}
|
||||
|
||||
if (mode==MODE_OPEN_DIR) {
|
||||
|
||||
|
||||
String path=dir_access->get_current_dir();
|
||||
/*if (tree->get_selected()) {
|
||||
Dictionary d = tree->get_selected()->get_metadata(0);
|
||||
if (d["dir"]) {
|
||||
path=path+"/"+String(d["name"]);
|
||||
}
|
||||
}*/
|
||||
path=path.replace("\\","/");
|
||||
emit_signal("dir_selected",path);
|
||||
hide();
|
||||
}
|
||||
|
||||
if (mode==MODE_SAVE_FILE) {
|
||||
|
||||
bool valid=false;
|
||||
|
||||
if (filter->get_selected()==filter->get_item_count()-1) {
|
||||
valid=true; //match none
|
||||
} else if (filters.size()>1 && filter->get_selected()==0) {
|
||||
// match all filters
|
||||
for (int i=0;i<filters.size();i++) {
|
||||
|
||||
String flt=filters[i].get_slice(";",0);
|
||||
for (int j=0;j<flt.get_slice_count(",");j++) {
|
||||
|
||||
String str = flt.get_slice(",",j).strip_edges();
|
||||
if (f.match(str)) {
|
||||
valid=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
int idx=filter->get_selected();
|
||||
if (filters.size()>1)
|
||||
idx--;
|
||||
if (idx>=0 && idx<filters.size()) {
|
||||
|
||||
String flt=filters[idx].get_slice(";",0);
|
||||
int filterSliceCount=flt.get_slice_count(",");
|
||||
for (int j=0;j<filterSliceCount;j++) {
|
||||
|
||||
String str = (flt.get_slice(",",j).strip_edges());
|
||||
if (f.match(str)) {
|
||||
valid=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid && filterSliceCount>0) {
|
||||
String str = (flt.get_slice(",",0).strip_edges());
|
||||
f+=str.substr(1, str.length()-1);
|
||||
_request_single_thumbnail(get_current_dir().plus_file(f.get_file()));
|
||||
file->set_text(f.get_file());
|
||||
valid=true;
|
||||
}
|
||||
} else {
|
||||
valid=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!valid) {
|
||||
|
||||
exterr->popup_centered_minsize(Size2(250,80));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
if (dir_access->file_exists(f)) {
|
||||
confirm_save->set_text("File Exists, Overwrite?");
|
||||
confirm_save->popup_centered(Size2(200,80));
|
||||
} else {
|
||||
|
||||
|
||||
emit_signal("file_selected",f);
|
||||
hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileDialog::_cancel_pressed() {
|
||||
|
||||
file->set_text("");
|
||||
invalidate();
|
||||
hide();
|
||||
}
|
||||
|
||||
void EditorFileDialog::_tree_selected() {
|
||||
|
||||
TreeItem *ti=tree->get_selected();
|
||||
if (!ti)
|
||||
return;
|
||||
Dictionary d=ti->get_metadata(0);
|
||||
|
||||
if (!d["dir"]) {
|
||||
|
||||
file->set_text(d["name"]);
|
||||
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileDialog::_tree_dc_selected() {
|
||||
|
||||
|
||||
TreeItem *ti=tree->get_selected();
|
||||
if (!ti)
|
||||
return;
|
||||
|
||||
Dictionary d=ti->get_metadata(0);
|
||||
|
||||
if (d["dir"]) {
|
||||
|
||||
dir_access->change_dir(d["name"]);
|
||||
if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR)
|
||||
file->set_text("");
|
||||
call_deferred("_update_file_list");
|
||||
call_deferred("_update_dir");
|
||||
} else {
|
||||
|
||||
_action_pressed();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorFileDialog::update_file_list() {
|
||||
|
||||
tree->clear();
|
||||
dir_access->list_dir_begin();
|
||||
|
||||
TreeItem *root = tree->create_item();
|
||||
Ref<Texture> folder = get_icon("folder","FileDialog");
|
||||
List<String> files;
|
||||
List<String> dirs;
|
||||
|
||||
bool isdir;
|
||||
bool ishidden;
|
||||
bool show_hidden = show_hidden_files;
|
||||
String item;
|
||||
|
||||
while ((item=dir_access->get_next(&isdir))!="") {
|
||||
|
||||
ishidden = dir_access->current_is_hidden();
|
||||
|
||||
if (show_hidden || !ishidden) {
|
||||
if (!isdir)
|
||||
files.push_back(item);
|
||||
else
|
||||
dirs.push_back(item);
|
||||
}
|
||||
}
|
||||
|
||||
dirs.sort_custom<NoCaseComparator>();
|
||||
files.sort_custom<NoCaseComparator>();
|
||||
|
||||
while(!dirs.empty()) {
|
||||
|
||||
if (dirs.front()->get()!=".") {
|
||||
TreeItem *ti=tree->create_item(root);
|
||||
ti->set_text(0,dirs.front()->get()+"/");
|
||||
ti->set_icon(0,folder);
|
||||
Dictionary d;
|
||||
d["name"]=dirs.front()->get();
|
||||
d["dir"]=true;
|
||||
ti->set_metadata(0,d);
|
||||
}
|
||||
dirs.pop_front();
|
||||
|
||||
}
|
||||
|
||||
dirs.clear();
|
||||
|
||||
List<String> patterns;
|
||||
// build filter
|
||||
if (filter->get_selected()==filter->get_item_count()-1) {
|
||||
|
||||
// match all
|
||||
} else if (filters.size()>1 && filter->get_selected()==0) {
|
||||
// match all filters
|
||||
for (int i=0;i<filters.size();i++) {
|
||||
|
||||
String f=filters[i].get_slice(";",0);
|
||||
for (int j=0;j<f.get_slice_count(",");j++) {
|
||||
|
||||
patterns.push_back(f.get_slice(",",j).strip_edges());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int idx=filter->get_selected();
|
||||
if (filters.size()>1)
|
||||
idx--;
|
||||
|
||||
if (idx>=0 && idx<filters.size()) {
|
||||
|
||||
String f=filters[idx].get_slice(";",0);
|
||||
for (int j=0;j<f.get_slice_count(",");j++) {
|
||||
|
||||
patterns.push_back(f.get_slice(",",j).strip_edges());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String base_dir = dir_access->get_current_dir();
|
||||
|
||||
|
||||
while(!files.empty()) {
|
||||
|
||||
bool match=patterns.empty();
|
||||
|
||||
for(List<String>::Element *E=patterns.front();E;E=E->next()) {
|
||||
|
||||
if (files.front()->get().matchn(E->get())) {
|
||||
|
||||
match=true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
TreeItem *ti=tree->create_item(root);
|
||||
ti->set_text(0,files.front()->get());
|
||||
|
||||
if (get_icon_func) {
|
||||
|
||||
Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get()));
|
||||
ti->set_icon(0,icon);
|
||||
}
|
||||
|
||||
if (mode==MODE_OPEN_DIR) {
|
||||
ti->set_custom_color(0,get_color("files_disabled"));
|
||||
ti->set_selectable(0,false);
|
||||
}
|
||||
Dictionary d;
|
||||
d["name"]=files.front()->get();
|
||||
d["dir"]=false;
|
||||
ti->set_metadata(0,d);
|
||||
|
||||
if (file->get_text()==files.front()->get())
|
||||
ti->select(0);
|
||||
}
|
||||
|
||||
files.pop_front();
|
||||
}
|
||||
|
||||
if (tree->get_root() && tree->get_root()->get_children())
|
||||
tree->get_root()->get_children()->select(0);
|
||||
|
||||
files.clear();
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_filter_selected(int) {
|
||||
|
||||
update_file_list();
|
||||
}
|
||||
|
||||
void EditorFileDialog::update_filters() {
|
||||
|
||||
filter->clear();
|
||||
|
||||
if (filters.size()>1) {
|
||||
String all_filters;
|
||||
|
||||
const int max_filters=5;
|
||||
|
||||
for(int i=0;i<MIN( max_filters, filters.size()) ;i++) {
|
||||
String flt=filters[i].get_slice(";",0);
|
||||
if (i>0)
|
||||
all_filters+=",";
|
||||
all_filters+=flt;
|
||||
}
|
||||
|
||||
if (max_filters<filters.size())
|
||||
all_filters+=", ...";
|
||||
|
||||
filter->add_item("All Recognized ( "+all_filters+" )");
|
||||
}
|
||||
for(int i=0;i<filters.size();i++) {
|
||||
|
||||
String flt=filters[i].get_slice(";",0).strip_edges();
|
||||
String desc=filters[i].get_slice(";",1).strip_edges();
|
||||
if (desc.length())
|
||||
filter->add_item(desc+" ( "+flt+" )");
|
||||
else
|
||||
filter->add_item("( "+flt+" )");
|
||||
}
|
||||
|
||||
filter->add_item("All Files (*)");
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::clear_filters() {
|
||||
|
||||
filters.clear();
|
||||
update_filters();
|
||||
invalidate();
|
||||
}
|
||||
void EditorFileDialog::add_filter(const String& p_filter) {
|
||||
|
||||
filters.push_back(p_filter);
|
||||
update_filters();
|
||||
invalidate();
|
||||
|
||||
}
|
||||
|
||||
String EditorFileDialog::get_current_dir() const {
|
||||
|
||||
return dir->get_text();
|
||||
}
|
||||
String EditorFileDialog::get_current_file() const {
|
||||
|
||||
return file->get_text();
|
||||
}
|
||||
String EditorFileDialog::get_current_path() const {
|
||||
|
||||
return dir->get_text().plus_file(file->get_text());
|
||||
}
|
||||
void EditorFileDialog::set_current_dir(const String& p_dir) {
|
||||
|
||||
dir_access->change_dir(p_dir);
|
||||
update_dir();
|
||||
invalidate();
|
||||
|
||||
}
|
||||
void EditorFileDialog::set_current_file(const String& p_file) {
|
||||
|
||||
file->set_text(p_file);
|
||||
update_dir();
|
||||
invalidate();
|
||||
int lp = p_file.find_last(".");
|
||||
if (lp!=-1) {
|
||||
file->select(0,lp);
|
||||
file->grab_focus();
|
||||
}
|
||||
|
||||
if (is_visible())
|
||||
_request_single_thumbnail(get_current_dir().plus_file(get_current_file()));
|
||||
|
||||
|
||||
}
|
||||
void EditorFileDialog::set_current_path(const String& p_path) {
|
||||
|
||||
if (!p_path.size())
|
||||
return;
|
||||
int pos=MAX( p_path.find_last("/"), p_path.find_last("\\") );
|
||||
if (pos==-1) {
|
||||
|
||||
set_current_file(p_path);
|
||||
} else {
|
||||
|
||||
String dir=p_path.substr(0,pos);
|
||||
String file=p_path.substr(pos+1,p_path.length());
|
||||
set_current_dir(dir);
|
||||
set_current_file(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EditorFileDialog::set_mode(Mode p_mode) {
|
||||
|
||||
mode=p_mode;
|
||||
switch(mode) {
|
||||
|
||||
case MODE_OPEN_FILE: get_ok()->set_text("Open"); set_title("Open a File"); makedir->hide(); break;
|
||||
case MODE_OPEN_FILES: get_ok()->set_text("Open"); set_title("Open File(s)"); makedir->hide(); break;
|
||||
case MODE_SAVE_FILE: get_ok()->set_text("Save"); set_title("Save a File"); makedir->show(); break;
|
||||
case MODE_OPEN_DIR: get_ok()->set_text("Open"); set_title("Open a Directory"); makedir->show(); break;
|
||||
}
|
||||
|
||||
if (mode==MODE_OPEN_FILES) {
|
||||
tree->set_select_mode(Tree::SELECT_MULTI);
|
||||
} else {
|
||||
tree->set_select_mode(Tree::SELECT_SINGLE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
EditorFileDialog::Mode EditorFileDialog::get_mode() const {
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
void EditorFileDialog::set_access(Access p_access) {
|
||||
|
||||
ERR_FAIL_INDEX(p_access,3);
|
||||
if (access==p_access)
|
||||
return;
|
||||
memdelete( dir_access );
|
||||
switch(p_access) {
|
||||
case ACCESS_FILESYSTEM: {
|
||||
|
||||
dir_access = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
|
||||
} break;
|
||||
case ACCESS_RESOURCES: {
|
||||
|
||||
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
} break;
|
||||
case ACCESS_USERDATA: {
|
||||
|
||||
dir_access = DirAccess::create(DirAccess::ACCESS_USERDATA);
|
||||
} break;
|
||||
}
|
||||
access=p_access;
|
||||
_update_drives();
|
||||
invalidate();
|
||||
update_filters();
|
||||
update_dir();
|
||||
}
|
||||
|
||||
void EditorFileDialog::invalidate() {
|
||||
|
||||
if (is_visible()) {
|
||||
update_file_list();
|
||||
invalidated=false;
|
||||
} else {
|
||||
invalidated=true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EditorFileDialog::Access EditorFileDialog::get_access() const{
|
||||
|
||||
return access;
|
||||
}
|
||||
|
||||
void EditorFileDialog::_make_dir_confirm() {
|
||||
|
||||
|
||||
Error err = dir_access->make_dir( makedirname->get_text() );
|
||||
if (err==OK) {
|
||||
dir_access->change_dir(makedirname->get_text());
|
||||
invalidate();
|
||||
update_filters();
|
||||
update_dir();
|
||||
} else {
|
||||
mkdirerr->popup_centered_minsize(Size2(250,50));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EditorFileDialog::_make_dir() {
|
||||
|
||||
makedialog->popup_centered_minsize(Size2(250,80));
|
||||
makedirname->grab_focus();
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_select_drive(int p_idx) {
|
||||
|
||||
String d = drives->get_item_text(p_idx);
|
||||
dir_access->change_dir(d);
|
||||
file->set_text("");
|
||||
invalidate();
|
||||
update_dir();
|
||||
|
||||
}
|
||||
|
||||
void EditorFileDialog::_update_drives() {
|
||||
|
||||
|
||||
int dc = dir_access->get_drive_count();
|
||||
if (dc==0 || access!=ACCESS_FILESYSTEM) {
|
||||
drives->hide();
|
||||
} else {
|
||||
drives->clear();
|
||||
drives->show();
|
||||
|
||||
for(int i=0;i<dir_access->get_drive_count();i++) {
|
||||
String d = dir_access->get_drive(i);
|
||||
drives->add_item(dir_access->get_drive(i));
|
||||
}
|
||||
|
||||
drives->select(dir_access->get_current_drive());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool EditorFileDialog::default_show_hidden_files=true;
|
||||
|
||||
|
||||
void EditorFileDialog::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_tree_selected"),&EditorFileDialog::_tree_selected);
|
||||
ObjectTypeDB::bind_method(_MD("_tree_db_selected"),&EditorFileDialog::_tree_dc_selected);
|
||||
ObjectTypeDB::bind_method(_MD("_dir_entered"),&EditorFileDialog::_dir_entered);
|
||||
ObjectTypeDB::bind_method(_MD("_file_entered"),&EditorFileDialog::_file_entered);
|
||||
ObjectTypeDB::bind_method(_MD("_action_pressed"),&EditorFileDialog::_action_pressed);
|
||||
ObjectTypeDB::bind_method(_MD("_cancel_pressed"),&EditorFileDialog::_cancel_pressed);
|
||||
ObjectTypeDB::bind_method(_MD("_filter_selected"),&EditorFileDialog::_filter_selected);
|
||||
ObjectTypeDB::bind_method(_MD("_save_confirm_pressed"),&EditorFileDialog::_save_confirm_pressed);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("clear_filters"),&EditorFileDialog::clear_filters);
|
||||
ObjectTypeDB::bind_method(_MD("add_filter","filter"),&EditorFileDialog::add_filter);
|
||||
ObjectTypeDB::bind_method(_MD("get_current_dir"),&EditorFileDialog::get_current_dir);
|
||||
ObjectTypeDB::bind_method(_MD("get_current_file"),&EditorFileDialog::get_current_file);
|
||||
ObjectTypeDB::bind_method(_MD("get_current_path"),&EditorFileDialog::get_current_path);
|
||||
ObjectTypeDB::bind_method(_MD("set_current_dir","dir"),&EditorFileDialog::set_current_dir);
|
||||
ObjectTypeDB::bind_method(_MD("set_current_file","file"),&EditorFileDialog::set_current_file);
|
||||
ObjectTypeDB::bind_method(_MD("set_current_path","path"),&EditorFileDialog::set_current_path);
|
||||
ObjectTypeDB::bind_method(_MD("set_mode","mode"),&EditorFileDialog::set_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_mode"),&EditorFileDialog::get_mode);
|
||||
ObjectTypeDB::bind_method(_MD("get_vbox:VBoxContainer"),&EditorFileDialog::get_vbox);
|
||||
ObjectTypeDB::bind_method(_MD("set_access","access"),&EditorFileDialog::set_access);
|
||||
ObjectTypeDB::bind_method(_MD("get_access"),&EditorFileDialog::get_access);
|
||||
ObjectTypeDB::bind_method(_MD("set_show_hidden_files"),&EditorFileDialog::set_show_hidden_files);
|
||||
ObjectTypeDB::bind_method(_MD("is_showing_hidden_files"),&EditorFileDialog::is_showing_hidden_files);
|
||||
ObjectTypeDB::bind_method(_MD("_select_drive"),&EditorFileDialog::_select_drive);
|
||||
ObjectTypeDB::bind_method(_MD("_make_dir"),&EditorFileDialog::_make_dir);
|
||||
ObjectTypeDB::bind_method(_MD("_make_dir_confirm"),&EditorFileDialog::_make_dir_confirm);
|
||||
ObjectTypeDB::bind_method(_MD("_update_file_list"),&EditorFileDialog::update_file_list);
|
||||
ObjectTypeDB::bind_method(_MD("_update_dir"),&EditorFileDialog::update_dir);
|
||||
ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&EditorFileDialog::_thumbnail_done);
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("invalidate"),&EditorFileDialog::invalidate);
|
||||
|
||||
ADD_SIGNAL(MethodInfo("file_selected",PropertyInfo( Variant::STRING,"path")));
|
||||
ADD_SIGNAL(MethodInfo("files_selected",PropertyInfo( Variant::STRING_ARRAY,"paths")));
|
||||
ADD_SIGNAL(MethodInfo("dir_selected",PropertyInfo( Variant::STRING,"dir")));
|
||||
|
||||
BIND_CONSTANT( MODE_OPEN_FILE );
|
||||
BIND_CONSTANT( MODE_OPEN_FILES );
|
||||
BIND_CONSTANT( MODE_OPEN_DIR );
|
||||
BIND_CONSTANT( MODE_SAVE_FILE );
|
||||
|
||||
BIND_CONSTANT( ACCESS_RESOURCES );
|
||||
BIND_CONSTANT( ACCESS_USERDATA );
|
||||
BIND_CONSTANT( ACCESS_FILESYSTEM );
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EditorFileDialog::set_show_hidden_files(bool p_show) {
|
||||
show_hidden_files=p_show;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
bool EditorFileDialog::is_showing_hidden_files() const {
|
||||
return show_hidden_files;
|
||||
}
|
||||
|
||||
void EditorFileDialog::set_default_show_hidden_files(bool p_show) {
|
||||
default_show_hidden_files=p_show;
|
||||
}
|
||||
|
||||
EditorFileDialog::EditorFileDialog() {
|
||||
|
||||
show_hidden_files=true;
|
||||
|
||||
VBoxContainer *vbc = memnew( VBoxContainer );
|
||||
add_child(vbc);
|
||||
set_child_rect(vbc);
|
||||
|
||||
mode=MODE_SAVE_FILE;
|
||||
set_title("Save a File");
|
||||
|
||||
dir = memnew(LineEdit);
|
||||
HBoxContainer *pathhb = memnew( HBoxContainer );
|
||||
pathhb->add_child(dir);
|
||||
dir->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
drives = memnew( OptionButton );
|
||||
pathhb->add_child(drives);
|
||||
drives->connect("item_selected",this,"_select_drive");
|
||||
|
||||
makedir = memnew( Button );
|
||||
makedir->set_text("Create Folder");
|
||||
makedir->connect("pressed",this,"_make_dir");
|
||||
pathhb->add_child(makedir);
|
||||
|
||||
vbc->add_margin_child("Path:",pathhb);
|
||||
|
||||
list_hb = memnew( HBoxContainer );
|
||||
vbc->add_margin_child("Directories & Files:",list_hb,true);
|
||||
|
||||
tree = memnew(Tree);
|
||||
tree->set_hide_root(true);
|
||||
tree->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
list_hb->add_child(tree);
|
||||
|
||||
HBoxContainer* filter_hb = memnew( HBoxContainer );
|
||||
vbc->add_child(filter_hb);
|
||||
|
||||
VBoxContainer *filter_vb = memnew( VBoxContainer );
|
||||
filter_hb->add_child(filter_vb);
|
||||
filter_vb->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
|
||||
preview_vb = memnew( VBoxContainer );
|
||||
filter_hb->add_child(preview_vb);
|
||||
CenterContainer *prev_cc = memnew( CenterContainer );
|
||||
preview_vb->add_margin_child("Preview:",prev_cc);
|
||||
preview = memnew( TextureFrame );
|
||||
prev_cc->add_child(preview);
|
||||
preview_vb->hide();
|
||||
|
||||
|
||||
file = memnew(LineEdit);
|
||||
//add_child(file);
|
||||
filter_vb->add_margin_child("File:",file);
|
||||
|
||||
|
||||
filter = memnew( OptionButton );
|
||||
//add_child(filter);
|
||||
filter_vb->add_margin_child("Filter:",filter);
|
||||
filter->set_clip_text(true);//too many extensions overflow it
|
||||
|
||||
dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES);
|
||||
access=ACCESS_RESOURCES;
|
||||
_update_drives();
|
||||
|
||||
|
||||
connect("confirmed", this,"_action_pressed");
|
||||
//cancel->connect("pressed", this,"_cancel_pressed");
|
||||
tree->connect("cell_selected", this,"_tree_selected",varray(),CONNECT_DEFERRED);
|
||||
tree->connect("item_activated", this,"_tree_db_selected",varray());
|
||||
dir->connect("text_entered", this,"_dir_entered");
|
||||
file->connect("text_entered", this,"_file_entered");
|
||||
filter->connect("item_selected", this,"_filter_selected");
|
||||
|
||||
|
||||
confirm_save = memnew( ConfirmationDialog );
|
||||
confirm_save->set_as_toplevel(true);
|
||||
add_child(confirm_save);
|
||||
|
||||
|
||||
confirm_save->connect("confirmed", this,"_save_confirm_pressed");
|
||||
|
||||
makedialog = memnew( ConfirmationDialog );
|
||||
makedialog->set_title("Create Folder");
|
||||
VBoxContainer *makevb= memnew( VBoxContainer );
|
||||
makedialog->add_child(makevb);
|
||||
makedialog->set_child_rect(makevb);
|
||||
makedirname = memnew( LineEdit );
|
||||
makevb->add_margin_child("Name:",makedirname);
|
||||
add_child(makedialog);
|
||||
makedialog->register_text_enter(makedirname);
|
||||
makedialog->connect("confirmed",this,"_make_dir_confirm");
|
||||
mkdirerr = memnew( AcceptDialog );
|
||||
mkdirerr->set_text("Could not create folder.");
|
||||
add_child(mkdirerr);
|
||||
|
||||
exterr = memnew( AcceptDialog );
|
||||
exterr->set_text("Must use a valid extension.");
|
||||
add_child(exterr);
|
||||
|
||||
|
||||
//update_file_list();
|
||||
update_filters();
|
||||
update_dir();
|
||||
|
||||
set_hide_on_ok(false);
|
||||
vbox=vbc;
|
||||
|
||||
|
||||
invalidated=true;
|
||||
if (register_func)
|
||||
register_func(this);
|
||||
|
||||
preview_wheel_timeout=0;
|
||||
preview_wheel_index=0;
|
||||
preview_waiting=false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
EditorFileDialog::~EditorFileDialog() {
|
||||
|
||||
if (unregister_func)
|
||||
unregister_func(this);
|
||||
memdelete(dir_access);
|
||||
}
|
||||
|
||||
|
||||
void EditorLineEditFileChooser::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method(_MD("_browse"),&EditorLineEditFileChooser::_browse);
|
||||
ObjectTypeDB::bind_method(_MD("_chosen"),&EditorLineEditFileChooser::_chosen);
|
||||
ObjectTypeDB::bind_method(_MD("get_button:Button"),&EditorLineEditFileChooser::get_button);
|
||||
ObjectTypeDB::bind_method(_MD("get_line_edit:LineEdit"),&EditorLineEditFileChooser::get_line_edit);
|
||||
ObjectTypeDB::bind_method(_MD("get_file_dialog:EditorFileDialog"),&EditorLineEditFileChooser::get_file_dialog);
|
||||
|
||||
}
|
||||
|
||||
void EditorLineEditFileChooser::_chosen(const String& p_text){
|
||||
|
||||
line_edit->set_text(p_text);
|
||||
line_edit->emit_signal("text_entered",p_text);
|
||||
}
|
||||
|
||||
void EditorLineEditFileChooser::_browse() {
|
||||
|
||||
dialog->popup_centered_ratio();
|
||||
}
|
||||
|
||||
EditorLineEditFileChooser::EditorLineEditFileChooser() {
|
||||
|
||||
line_edit = memnew( LineEdit );
|
||||
add_child(line_edit);
|
||||
line_edit->set_h_size_flags(SIZE_EXPAND_FILL);
|
||||
button = memnew( Button );
|
||||
button->set_text(" .. ");
|
||||
add_child(button);
|
||||
button->connect("pressed",this,"_browse");
|
||||
dialog = memnew( EditorFileDialog);
|
||||
add_child(dialog);
|
||||
dialog->connect("file_selected",this,"_chosen");
|
||||
dialog->connect("dir_selected",this,"_chosen");
|
||||
dialog->connect("files_selected",this,"_chosen");
|
||||
|
||||
}
|
198
tools/editor/editor_file_dialog.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*************************************************************************/
|
||||
/* file_dialog.h */
|
||||
/*************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* http://www.godotengine.org */
|
||||
/*************************************************************************/
|
||||
/* Copyright (c) 2007-2015 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/*************************************************************************/
|
||||
|
||||
|
||||
#ifndef EDITORFILEDIALOG_H
|
||||
#define EDITORFILEDIALOG_H
|
||||
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "scene/gui/tree.h"
|
||||
#include "scene/gui/line_edit.h"
|
||||
#include "scene/gui/option_button.h"
|
||||
#include "scene/gui/dialogs.h"
|
||||
#include "os/dir_access.h"
|
||||
#include "scene/gui/box_container.h"
|
||||
#include "scene/gui/texture_frame.h"
|
||||
|
||||
/**
|
||||
@author Juan Linietsky <reduzio@gmail.com>
|
||||
*/
|
||||
class EditorFileDialog : public ConfirmationDialog {
|
||||
|
||||
OBJ_TYPE( EditorFileDialog, ConfirmationDialog );
|
||||
|
||||
public:
|
||||
|
||||
enum Access {
|
||||
ACCESS_RESOURCES,
|
||||
ACCESS_USERDATA,
|
||||
ACCESS_FILESYSTEM
|
||||
};
|
||||
|
||||
|
||||
enum Mode {
|
||||
MODE_OPEN_FILE,
|
||||
MODE_OPEN_FILES,
|
||||
MODE_OPEN_DIR,
|
||||
MODE_SAVE_FILE,
|
||||
};
|
||||
|
||||
typedef Ref<Texture> (*GetIconFunc)(const String&);
|
||||
typedef void (*RegisterFunc)(EditorFileDialog*);
|
||||
|
||||
static GetIconFunc get_icon_func;
|
||||
static GetIconFunc get_large_icon_func;
|
||||
static RegisterFunc register_func;
|
||||
static RegisterFunc unregister_func;
|
||||
|
||||
private:
|
||||
|
||||
ConfirmationDialog *makedialog;
|
||||
LineEdit *makedirname;
|
||||
|
||||
Button *makedir;
|
||||
Access access;
|
||||
//Button *action;
|
||||
VBoxContainer *vbox;
|
||||
Mode mode;
|
||||
LineEdit *dir;
|
||||
OptionButton *drives;
|
||||
Tree *tree;
|
||||
TextureFrame *preview;
|
||||
VBoxContainer *preview_vb;
|
||||
HBoxContainer *list_hb;
|
||||
LineEdit *file;
|
||||
AcceptDialog *mkdirerr;
|
||||
AcceptDialog *exterr;
|
||||
OptionButton *filter;
|
||||
DirAccess *dir_access;
|
||||
ConfirmationDialog *confirm_save;
|
||||
|
||||
Vector<String> filters;
|
||||
|
||||
bool preview_waiting;
|
||||
int preview_wheel_index;
|
||||
float preview_wheel_timeout;
|
||||
static bool default_show_hidden_files;
|
||||
bool show_hidden_files;
|
||||
|
||||
bool invalidated;
|
||||
|
||||
void update_dir();
|
||||
void update_file_list();
|
||||
void update_filters();
|
||||
|
||||
void _tree_selected();
|
||||
|
||||
void _select_drive(int p_idx);
|
||||
void _tree_dc_selected();
|
||||
void _dir_entered(String p_dir);
|
||||
void _file_entered(const String& p_file);
|
||||
void _action_pressed();
|
||||
void _save_confirm_pressed();
|
||||
void _cancel_pressed();
|
||||
void _filter_selected(int);
|
||||
void _make_dir();
|
||||
void _make_dir_confirm();
|
||||
|
||||
void _update_drives();
|
||||
|
||||
virtual void _post_popup();
|
||||
|
||||
|
||||
//callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
|
||||
|
||||
void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata);
|
||||
void _request_single_thumbnail(const String& p_path);
|
||||
|
||||
protected:
|
||||
|
||||
void _notification(int p_what);
|
||||
static void _bind_methods();
|
||||
//bind helpers
|
||||
public:
|
||||
|
||||
void clear_filters();
|
||||
void add_filter(const String& p_filter);
|
||||
|
||||
void set_enable_multiple_selection(bool p_enable);
|
||||
Vector<String> get_selected_files() const;
|
||||
|
||||
String get_current_dir() const;
|
||||
String get_current_file() const;
|
||||
String get_current_path() const;
|
||||
void set_current_dir(const String& p_dir);
|
||||
void set_current_file(const String& p_file);
|
||||
void set_current_path(const String& p_path);
|
||||
|
||||
void set_mode(Mode p_mode);
|
||||
Mode get_mode() const;
|
||||
|
||||
VBoxContainer *get_vbox();
|
||||
LineEdit *get_line_edit() { return file; }
|
||||
|
||||
void set_access(Access p_access);
|
||||
Access get_access() const;
|
||||
|
||||
void set_show_hidden_files(bool p_show);
|
||||
bool is_showing_hidden_files() const;
|
||||
|
||||
static void set_default_show_hidden_files(bool p_show);
|
||||
|
||||
void invalidate();
|
||||
|
||||
EditorFileDialog();
|
||||
~EditorFileDialog();
|
||||
|
||||
};
|
||||
|
||||
class EditorLineEditFileChooser : public HBoxContainer {
|
||||
|
||||
OBJ_TYPE( EditorLineEditFileChooser, HBoxContainer );
|
||||
Button *button;
|
||||
LineEdit *line_edit;
|
||||
EditorFileDialog *dialog;
|
||||
|
||||
void _chosen(const String& p_text);
|
||||
void _browse();
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
Button *get_button() { return button; }
|
||||
LineEdit *get_line_edit() { return line_edit; }
|
||||
EditorFileDialog *get_file_dialog() { return dialog; }
|
||||
|
||||
EditorLineEditFileChooser();
|
||||
};
|
||||
|
||||
VARIANT_ENUM_CAST( EditorFileDialog::Mode );
|
||||
VARIANT_ENUM_CAST( EditorFileDialog::Access );
|
||||
|
||||
#endif // EDITORFILEDIALOG_H
|
|
@ -99,6 +99,7 @@
|
|||
#include "tools/editor/io_plugins/editor_translation_import_plugin.h"
|
||||
#include "tools/editor/io_plugins/editor_mesh_import_plugin.h"
|
||||
|
||||
#include "plugins/editor_preview_plugins.h"
|
||||
|
||||
|
||||
EditorNode *EditorNode::singleton=NULL;
|
||||
|
@ -320,6 +321,11 @@ void EditorNode::_fs_changed() {
|
|||
|
||||
E->get()->invalidate();
|
||||
}
|
||||
|
||||
for(Set<EditorFileDialog*>::Element *E=editor_file_dialogs.front();E;E=E->next()) {
|
||||
|
||||
E->get()->invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
void EditorNode::_sources_changed(bool p_exist) {
|
||||
|
@ -386,7 +392,7 @@ void EditorNode::edit_node(Node *p_node) {
|
|||
void EditorNode::open_resource(const String& p_type) {
|
||||
|
||||
|
||||
file->set_mode(FileDialog::MODE_OPEN_FILE);
|
||||
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
|
||||
|
||||
List<String> extensions;
|
||||
ResourceLoader::get_recognized_extensions_for_type(p_type,&extensions);
|
||||
|
@ -718,6 +724,96 @@ void EditorNode::_save_edited_subresources(Node* scene,Map<RES,bool>& processed,
|
|||
|
||||
}
|
||||
|
||||
void EditorNode::_find_node_types(Node* p_node, int&count_2d, int&count_3d) {
|
||||
|
||||
if (p_node->is_type("Viewport") || (p_node!=get_edited_scene() && p_node->get_owner()!=get_edited_scene()))
|
||||
return;
|
||||
|
||||
if (p_node->is_type("CanvasItem"))
|
||||
count_2d++;
|
||||
else if (p_node->is_type("Spatial"))
|
||||
count_3d++;
|
||||
|
||||
for(int i=0;i<p_node->get_child_count();i++)
|
||||
_find_node_types(p_node->get_child(i),count_2d,count_3d);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EditorNode::_save_scene_with_preview(String p_file) {
|
||||
|
||||
int c2d=0;
|
||||
int c3d=0;
|
||||
|
||||
EditorProgress save("save","Saving Scene",4);
|
||||
save.step("Analyzing",0);
|
||||
_find_node_types(get_edited_scene(),c2d,c3d);
|
||||
|
||||
RID viewport;
|
||||
bool is2d;
|
||||
if (c3d<c2d) {
|
||||
viewport=scene_root->get_viewport();
|
||||
is2d=true;
|
||||
} else {
|
||||
viewport=SpatialEditor::get_singleton()->get_editor_viewport(0)->get_viewport_node()->get_viewport();
|
||||
is2d=false;
|
||||
|
||||
}
|
||||
save.step("Creating Thumbnail",1);
|
||||
//current view?
|
||||
int screen =-1;
|
||||
for(int i=0;i<editor_table.size();i++) {
|
||||
if (editor_plugin_screen==editor_table[i]) {
|
||||
screen=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_editor_select(is2d?0:1);
|
||||
|
||||
VS::get_singleton()->viewport_queue_screen_capture(viewport);
|
||||
save.step("Creating Thumbnail",2);
|
||||
save.step("Creating Thumbnail",3);
|
||||
Image img = VS::get_singleton()->viewport_get_screen_capture(viewport);
|
||||
int preview_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");;
|
||||
int width,height;
|
||||
if (img.get_width() > preview_size && img.get_width() >= img.get_height()) {
|
||||
|
||||
width=preview_size;
|
||||
height = img.get_height() * preview_size / img.get_width();
|
||||
} else if (img.get_height() > preview_size && img.get_height() >= img.get_width()) {
|
||||
|
||||
height=preview_size;
|
||||
width = img.get_width() * preview_size / img.get_height();
|
||||
} else {
|
||||
|
||||
width=img.get_width();
|
||||
height=img.get_height();
|
||||
}
|
||||
|
||||
img.convert(Image::FORMAT_RGB);
|
||||
img.resize(width,height);
|
||||
|
||||
String pfile = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/last_scene_preview.png");
|
||||
img.save_png(pfile);
|
||||
Vector<uint8_t> imgdata = FileAccess::get_file_as_array(pfile);
|
||||
|
||||
print_line("img data is "+itos(imgdata.size()));
|
||||
|
||||
if (scene_import_metadata.is_null())
|
||||
scene_import_metadata = Ref<ResourceImportMetadata>( memnew( ResourceImportMetadata ) );
|
||||
scene_import_metadata->set_option("thumbnail",imgdata);
|
||||
|
||||
//tamanio tel thumbnail
|
||||
if (screen!=-1) {
|
||||
_editor_select(screen);
|
||||
}
|
||||
save.step("Saving Scene",4);
|
||||
_save_scene(p_file);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EditorNode::_save_scene(String p_file) {
|
||||
|
||||
Node *scene = edited_scene;
|
||||
|
@ -1016,7 +1112,9 @@ void EditorNode::_dialog_action(String p_file) {
|
|||
|
||||
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
|
||||
|
||||
_save_scene(p_file);
|
||||
//_save_scene(p_file);
|
||||
_save_scene_with_preview(p_file);
|
||||
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -1024,7 +1122,8 @@ void EditorNode::_dialog_action(String p_file) {
|
|||
case FILE_SAVE_AND_RUN: {
|
||||
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
|
||||
|
||||
_save_scene(p_file);
|
||||
//_save_scene(p_file);
|
||||
_save_scene_with_preview(p_file);
|
||||
_run(false);
|
||||
}
|
||||
} break;
|
||||
|
@ -1177,7 +1276,8 @@ void EditorNode::_dialog_action(String p_file) {
|
|||
|
||||
if (file->get_mode()==FileDialog::MODE_SAVE_FILE) {
|
||||
|
||||
_save_scene(p_file);
|
||||
//_save_scene(p_file);
|
||||
_save_scene_with_preview(p_file);
|
||||
}
|
||||
|
||||
} break;
|
||||
|
@ -1505,7 +1605,8 @@ void EditorNode::_run(bool p_current,const String& p_custom) {
|
|||
return;
|
||||
}
|
||||
|
||||
_save_scene(scene->get_filename());
|
||||
//_save_scene(scene->get_filename());
|
||||
_save_scene_with_preview(scene->get_filename());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1608,7 +1709,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
|
||||
|
||||
//print_tree();
|
||||
file->set_mode(FileDialog::MODE_OPEN_FILE);
|
||||
file->set_mode(EditorFileDialog::MODE_OPEN_FILE);
|
||||
//not for now?
|
||||
List<String> extensions;
|
||||
ResourceLoader::get_recognized_extensions_for_type("PackedScene",&extensions);
|
||||
|
@ -1659,7 +1760,8 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
Node *scene = edited_scene;
|
||||
if (scene && scene->get_filename()!="") {
|
||||
|
||||
_save_scene(scene->get_filename());
|
||||
//_save_scene(scene->get_filename());
|
||||
_save_scene_with_preview(scene->get_filename());
|
||||
return;
|
||||
};
|
||||
// fallthrough to save_as
|
||||
|
@ -1678,7 +1780,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
break;
|
||||
}
|
||||
|
||||
file->set_mode(FileDialog::MODE_SAVE_FILE);
|
||||
file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
|
||||
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
|
||||
|
||||
|
||||
|
@ -1761,7 +1863,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
|
||||
bool relpaths = (scene->has_meta("__editor_relpaths__") && scene->get_meta("__editor_relpaths__").operator bool());
|
||||
|
||||
file->set_mode(FileDialog::MODE_SAVE_FILE);
|
||||
file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
|
||||
|
||||
file->set_current_path(cpath);
|
||||
file->set_title("Save Translatable Strings");
|
||||
|
@ -1810,7 +1912,7 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) {
|
|||
break;
|
||||
}
|
||||
|
||||
file->set_mode(FileDialog::MODE_SAVE_FILE);
|
||||
file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
|
||||
|
||||
List<String> extensions;
|
||||
Ref<PackedScene> sd = memnew( PackedScene );
|
||||
|
@ -3132,6 +3234,7 @@ void EditorNode::register_editor_types() {
|
|||
ObjectTypeDB::register_type<EditorImportPlugin>();
|
||||
ObjectTypeDB::register_type<EditorScenePostImport>();
|
||||
ObjectTypeDB::register_type<EditorScript>();
|
||||
ObjectTypeDB::register_type<EditorFileDialog>();
|
||||
|
||||
|
||||
//ObjectTypeDB::register_type<EditorImporter>();
|
||||
|
@ -3282,6 +3385,16 @@ void EditorNode::_file_dialog_unregister(FileDialog *p_dialog){
|
|||
singleton->file_dialogs.erase(p_dialog);
|
||||
}
|
||||
|
||||
void EditorNode::_editor_file_dialog_register(EditorFileDialog *p_dialog) {
|
||||
|
||||
singleton->editor_file_dialogs.insert(p_dialog);
|
||||
}
|
||||
|
||||
void EditorNode::_editor_file_dialog_unregister(EditorFileDialog *p_dialog){
|
||||
|
||||
singleton->editor_file_dialogs.erase(p_dialog);
|
||||
}
|
||||
|
||||
Vector<EditorNodeInitCallback> EditorNode::_init_callbacks;
|
||||
|
||||
Error EditorNode::export_platform(const String& p_platform, const String& p_path, bool p_debug,const String& p_password,bool p_quit_after) {
|
||||
|
@ -3334,6 +3447,11 @@ EditorNode::EditorNode() {
|
|||
FileDialog::register_func=_file_dialog_register;
|
||||
FileDialog::unregister_func=_file_dialog_unregister;
|
||||
|
||||
EditorFileDialog::get_icon_func=_file_dialog_get_icon;
|
||||
EditorFileDialog::register_func=_editor_file_dialog_register;
|
||||
EditorFileDialog::unregister_func=_editor_file_dialog_unregister;
|
||||
|
||||
|
||||
editor_import_export = memnew( EditorImportExport );
|
||||
add_child(editor_import_export);
|
||||
|
||||
|
@ -3358,6 +3476,9 @@ EditorNode::EditorNode() {
|
|||
editor_register_icons(theme);
|
||||
editor_register_fonts(theme);
|
||||
|
||||
//theme->set_icon("folder","EditorFileDialog",Theme::get_default()->get_icon("folder","EditorFileDialog"));
|
||||
//theme->set_color("files_disabled","EditorFileDialog",Color(0,0,0,0.7));
|
||||
|
||||
String global_font = EditorSettings::get_singleton()->get("global/font");
|
||||
if (global_font!="") {
|
||||
Ref<Font> fnt = ResourceLoader::load(global_font);
|
||||
|
@ -3376,6 +3497,8 @@ EditorNode::EditorNode() {
|
|||
theme->set_stylebox("EditorFocus","EditorStyles",focus_sbt);
|
||||
|
||||
|
||||
resource_preview = memnew( EditorResourcePreview );
|
||||
add_child(resource_preview);
|
||||
progress_dialog = memnew( ProgressDialog );
|
||||
gui_base->add_child(progress_dialog);
|
||||
|
||||
|
@ -3473,6 +3596,7 @@ EditorNode::EditorNode() {
|
|||
animation_panel=pc;
|
||||
animation_panel->hide();
|
||||
|
||||
|
||||
HBoxContainer *animation_hb = memnew( HBoxContainer);
|
||||
animation_vb->add_child(animation_hb);
|
||||
|
||||
|
@ -4031,7 +4155,7 @@ EditorNode::EditorNode() {
|
|||
file_templates->add_filter("*.tpz ; Template Package");
|
||||
|
||||
|
||||
file = memnew( FileDialog );
|
||||
file = memnew( EditorFileDialog );
|
||||
gui_base->add_child(file);
|
||||
file->set_current_dir("res://");
|
||||
|
||||
|
@ -4161,6 +4285,13 @@ EditorNode::EditorNode() {
|
|||
for(int i=0;i<EditorPlugins::get_plugin_count();i++)
|
||||
add_editor_plugin( EditorPlugins::create(i,this) );
|
||||
|
||||
|
||||
resource_preview->add_preview_generator( Ref<EditorTexturePreviewPlugin>( memnew(EditorTexturePreviewPlugin )));
|
||||
resource_preview->add_preview_generator( Ref<EditorPackedScenePreviewPlugin>( memnew(EditorPackedScenePreviewPlugin )));
|
||||
resource_preview->add_preview_generator( Ref<EditorMaterialPreviewPlugin>( memnew(EditorMaterialPreviewPlugin )));
|
||||
resource_preview->add_preview_generator( Ref<EditorScriptPreviewPlugin>( memnew(EditorScriptPreviewPlugin )));
|
||||
resource_preview->add_preview_generator( Ref<EditorSamplePreviewPlugin>( memnew(EditorSamplePreviewPlugin )));
|
||||
|
||||
circle_step_msec=OS::get_singleton()->get_ticks_msec();
|
||||
circle_step_frame=OS::get_singleton()->get_frames_drawn();;
|
||||
circle_step=0;
|
||||
|
|
|
@ -78,7 +78,7 @@
|
|||
#include "tools/editor/editor_plugin.h"
|
||||
|
||||
#include "fileserver/editor_file_server.h"
|
||||
|
||||
#include "editor_resource_preview.h"
|
||||
|
||||
|
||||
|
||||
|
@ -238,7 +238,7 @@ class EditorNode : public Node {
|
|||
EditorSettingsDialog *settings_config_dialog;
|
||||
RunSettingsDialog *run_settings_dialog;
|
||||
ProjectSettings *project_settings;
|
||||
FileDialog *file;
|
||||
EditorFileDialog *file;
|
||||
FileDialog *file_templates;
|
||||
FileDialog *file_export;
|
||||
FileDialog *file_export_lib;
|
||||
|
@ -304,6 +304,7 @@ class EditorNode : public Node {
|
|||
EditorSelection *editor_selection;
|
||||
ProjectExport *project_export;
|
||||
ProjectExportDialog *project_export_settings;
|
||||
EditorResourcePreview *resource_preview;
|
||||
|
||||
EditorFileServer *file_server;
|
||||
|
||||
|
@ -381,11 +382,15 @@ class EditorNode : public Node {
|
|||
String import_reload_fn;
|
||||
|
||||
Set<FileDialog*> file_dialogs;
|
||||
Set<EditorFileDialog*> editor_file_dialogs;
|
||||
|
||||
Map<String,Ref<Texture> > icon_type_cache;
|
||||
|
||||
static Ref<Texture> _file_dialog_get_icon(const String& p_path);
|
||||
static void _file_dialog_register(FileDialog *p_dialog);
|
||||
static void _file_dialog_unregister(FileDialog *p_dialog);
|
||||
static void _editor_file_dialog_register(EditorFileDialog *p_dialog);
|
||||
static void _editor_file_dialog_unregister(EditorFileDialog *p_dialog);
|
||||
|
||||
|
||||
void _cleanup_scene();
|
||||
|
@ -394,6 +399,9 @@ class EditorNode : public Node {
|
|||
bool _find_and_save_edited_subresources(Object *obj,Map<RES,bool>& processed,int32_t flags);
|
||||
void _save_edited_subresources(Node* scene,Map<RES,bool>& processed,int32_t flags);
|
||||
|
||||
void _find_node_types(Node* p_node, int&count_2d, int&count_3d);
|
||||
void _save_scene_with_preview(String p_file);
|
||||
|
||||
|
||||
struct ExportDefer {
|
||||
String platform;
|
||||
|
|
260
tools/editor/editor_resource_preview.cpp
Normal file
|
@ -0,0 +1,260 @@
|
|||
#include "editor_resource_preview.h"
|
||||
#include "editor_settings.h"
|
||||
#include "os/file_access.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "io/resource_saver.h"
|
||||
#include "globals.h"
|
||||
|
||||
|
||||
Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String& p_path) {
|
||||
|
||||
RES res = ResourceLoader::load(p_path);
|
||||
if (!res.is_valid())
|
||||
return res;
|
||||
return generate(res);
|
||||
}
|
||||
|
||||
EditorResourcePreviewGenerator::EditorResourcePreviewGenerator() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
EditorResourcePreview* EditorResourcePreview::singleton=NULL;
|
||||
|
||||
|
||||
void EditorResourcePreview::_thread_func(void *ud) {
|
||||
|
||||
EditorResourcePreview *erp=(EditorResourcePreview*)ud;
|
||||
erp->_thread();
|
||||
|
||||
}
|
||||
|
||||
|
||||
void EditorResourcePreview::_preview_ready(const String& p_str,const Ref<Texture>& p_texture,ObjectID id,const StringName& p_func,const Variant& p_ud) {
|
||||
|
||||
print_line("preview is ready");
|
||||
preview_mutex->lock();
|
||||
|
||||
Item item;
|
||||
item.order=order++;
|
||||
item.preview=p_texture;
|
||||
cache[p_str]=item;
|
||||
|
||||
Object *recv = ObjectDB::get_instance(id);
|
||||
if (recv) {
|
||||
recv->call_deferred(p_func,p_str,p_texture,p_ud);
|
||||
}
|
||||
|
||||
preview_mutex->unlock();
|
||||
}
|
||||
|
||||
Ref<Texture> EditorResourcePreview::_generate_preview(const QueueItem& p_item,const String& cache_base) {
|
||||
|
||||
String type = ResourceLoader::get_resource_type(p_item.path);
|
||||
print_line("resource type is: "+type);
|
||||
|
||||
if (type=="")
|
||||
return Ref<Texture>(); //could not guess type
|
||||
|
||||
Ref<Texture> generated;
|
||||
|
||||
for(int i=0;i<preview_generators.size();i++) {
|
||||
if (!preview_generators[i]->handles(type))
|
||||
continue;
|
||||
generated = preview_generators[i]->generate_from_path(p_item.path);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (generated.is_valid()) {
|
||||
print_line("was generated");
|
||||
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
|
||||
//wow it generated a preview... save cache
|
||||
ResourceSaver::save(cache_base+".png",generated);
|
||||
FileAccess *f=FileAccess::open(cache_base+".txt",FileAccess::WRITE);
|
||||
f->store_line(itos(thumbnail_size));
|
||||
f->store_line(itos(FileAccess::get_modified_time(p_item.path)));
|
||||
f->store_line(FileAccess::get_md5(p_item.path));
|
||||
memdelete(f);
|
||||
} else {
|
||||
print_line("was not generated");
|
||||
|
||||
}
|
||||
|
||||
return generated;
|
||||
}
|
||||
|
||||
void EditorResourcePreview::_thread() {
|
||||
|
||||
print_line("begin thread");
|
||||
while(!exit) {
|
||||
|
||||
print_line("wait for semaphore");
|
||||
preview_sem->wait();
|
||||
preview_mutex->lock();
|
||||
|
||||
print_line("blue team go");
|
||||
|
||||
if (queue.size()) {
|
||||
|
||||
print_line("pop from queue");
|
||||
|
||||
QueueItem item = queue.front()->get();
|
||||
queue.pop_front();
|
||||
preview_mutex->unlock();
|
||||
|
||||
Ref<Texture> texture;
|
||||
|
||||
|
||||
uint64_t modtime = FileAccess::get_modified_time(item.path);
|
||||
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
|
||||
|
||||
if (cache.has(item.path)) {
|
||||
//already has it because someone loaded it, just let it know it's ready
|
||||
call_deferred("_preview_ready",item.path,cache[item.path].preview,item.id,item.function,item.userdata);
|
||||
|
||||
} else {
|
||||
|
||||
|
||||
String temp_path=EditorSettings::get_singleton()->get_settings_path().plus_file("tmp");
|
||||
String cache_base = Globals::get_singleton()->globalize_path(item.path).md5_text();
|
||||
cache_base = temp_path.plus_file("resthumb-"+cache_base);
|
||||
|
||||
//does not have it, try to load a cached thumbnail
|
||||
|
||||
String file = cache_base+".txt";
|
||||
print_line("cachetxt at "+file);
|
||||
FileAccess *f=FileAccess::open(file,FileAccess::READ);
|
||||
if (!f) {
|
||||
|
||||
print_line("generate because not cached");
|
||||
|
||||
//generate
|
||||
texture=_generate_preview(item,cache_base);
|
||||
} else {
|
||||
|
||||
int tsize = f->get_line().to_int64();
|
||||
uint64_t last_modtime = f->get_line().to_int64();
|
||||
|
||||
bool cache_valid = true;
|
||||
|
||||
if (tsize!=thumbnail_size) {
|
||||
cache_valid=false;
|
||||
memdelete(f);
|
||||
} else if (last_modtime!=modtime) {
|
||||
|
||||
String last_md5 = f->get_line();
|
||||
String md5 = FileAccess::get_md5(item.path);
|
||||
memdelete(f);
|
||||
|
||||
if (last_md5!=md5) {
|
||||
|
||||
cache_valid=false;
|
||||
} else {
|
||||
//update modified time
|
||||
|
||||
f=FileAccess::open(file,FileAccess::WRITE);
|
||||
f->store_line(itos(modtime));
|
||||
f->store_line(md5);
|
||||
memdelete(f);
|
||||
}
|
||||
} else {
|
||||
memdelete(f);
|
||||
}
|
||||
|
||||
if (cache_valid) {
|
||||
|
||||
texture = ResourceLoader::load(cache_base+".png","ImageTexture",true);
|
||||
if (!texture.is_valid()) {
|
||||
//well fuck
|
||||
cache_valid=false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cache_valid) {
|
||||
|
||||
texture=_generate_preview(item,cache_base);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
print_line("notify of preview ready");
|
||||
call_deferred("_preview_ready",item.path,texture,item.id,item.function,item.userdata);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
preview_mutex->unlock();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void EditorResourcePreview::queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata) {
|
||||
|
||||
ERR_FAIL_NULL(p_receiver);
|
||||
preview_mutex->lock();
|
||||
if (cache.has(p_path)) {
|
||||
cache[p_path].order=order++;
|
||||
p_receiver->call_deferred(p_receiver_func,p_path,cache[p_path].preview,p_userdata);
|
||||
preview_mutex->unlock();
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
print_line("send to thread");
|
||||
QueueItem item;
|
||||
item.function=p_receiver_func;
|
||||
item.id=p_receiver->get_instance_ID();
|
||||
item.path=p_path;
|
||||
item.userdata=p_userdata;
|
||||
|
||||
queue.push_back(item);
|
||||
preview_mutex->unlock();
|
||||
preview_sem->post();
|
||||
|
||||
}
|
||||
|
||||
void EditorResourcePreview::add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator) {
|
||||
|
||||
preview_generators.push_back(p_generator);
|
||||
}
|
||||
|
||||
EditorResourcePreview* EditorResourcePreview::get_singleton() {
|
||||
|
||||
return singleton;
|
||||
}
|
||||
|
||||
void EditorResourcePreview::_bind_methods() {
|
||||
|
||||
ObjectTypeDB::bind_method("_preview_ready",&EditorResourcePreview::_preview_ready);
|
||||
}
|
||||
|
||||
EditorResourcePreview::EditorResourcePreview() {
|
||||
singleton=this;
|
||||
preview_mutex = Mutex::create();
|
||||
preview_sem = Semaphore::create();
|
||||
order=0;
|
||||
exit=false;
|
||||
|
||||
thread = Thread::create(_thread_func,this);
|
||||
}
|
||||
|
||||
|
||||
EditorResourcePreview::~EditorResourcePreview()
|
||||
{
|
||||
|
||||
exit=true;
|
||||
preview_sem->post();
|
||||
Thread::wait_to_finish(thread);
|
||||
memdelete(thread);
|
||||
memdelete(preview_mutex);
|
||||
memdelete(preview_sem);
|
||||
|
||||
|
||||
}
|
||||
|
95
tools/editor/editor_resource_preview.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#ifndef EDITORRESOURCEPREVIEW_H
|
||||
#define EDITORRESOURCEPREVIEW_H
|
||||
|
||||
#include "scene/main/node.h"
|
||||
#include "os/semaphore.h"
|
||||
#include "os/thread.h"
|
||||
#include "scene/resources/texture.h"
|
||||
|
||||
/* make previews for:
|
||||
*packdscene
|
||||
-wav
|
||||
*image
|
||||
-mesh
|
||||
-font
|
||||
*script
|
||||
*material
|
||||
-shader
|
||||
-shader graph?
|
||||
-navigation mesh
|
||||
-collision?
|
||||
-occluder polygon
|
||||
-navigation polygon
|
||||
-tileset
|
||||
-curve and curve2D
|
||||
*/
|
||||
|
||||
|
||||
class EditorResourcePreviewGenerator : public Reference {
|
||||
|
||||
OBJ_TYPE(EditorResourcePreviewGenerator,Reference );
|
||||
|
||||
public:
|
||||
|
||||
virtual bool handles(const String& p_type) const=0;
|
||||
virtual Ref<Texture> generate(const RES& p_from)=0;
|
||||
virtual Ref<Texture> generate_from_path(const String& p_path);
|
||||
|
||||
EditorResourcePreviewGenerator();
|
||||
};
|
||||
|
||||
|
||||
class EditorResourcePreview : public Node {
|
||||
|
||||
OBJ_TYPE(EditorResourcePreview,Node);
|
||||
|
||||
|
||||
static EditorResourcePreview* singleton;
|
||||
|
||||
struct QueueItem {
|
||||
String path;
|
||||
ObjectID id;
|
||||
StringName function;
|
||||
Variant userdata;
|
||||
};
|
||||
|
||||
List<QueueItem> queue;
|
||||
|
||||
Mutex *preview_mutex;
|
||||
Semaphore *preview_sem;
|
||||
Thread *thread;
|
||||
bool exit;
|
||||
|
||||
struct Item {
|
||||
Ref<Texture> preview;
|
||||
int order;
|
||||
};
|
||||
|
||||
int order;
|
||||
|
||||
Map<String,Item> cache;
|
||||
|
||||
void _preview_ready(const String& p_str,const Ref<Texture>& p_texture, ObjectID id, const StringName &p_func, const Variant &p_ud);
|
||||
Ref<Texture> _generate_preview(const QueueItem& p_item, const String &cache_base);
|
||||
|
||||
static void _thread_func(void *ud);
|
||||
void _thread();
|
||||
|
||||
Vector<Ref<EditorResourcePreviewGenerator> > preview_generators;
|
||||
protected:
|
||||
|
||||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
static EditorResourcePreview* get_singleton();
|
||||
|
||||
//callback funtion is callback(String p_path,Ref<Texture> preview,Variant udata) preview null if could not load
|
||||
void queue_resource_preview(const String& p_path, Object* p_receiver, const StringName& p_receiver_func, const Variant& p_userdata);
|
||||
|
||||
void add_preview_generator(const Ref<EditorResourcePreviewGenerator>& p_generator);
|
||||
|
||||
EditorResourcePreview();
|
||||
~EditorResourcePreview();
|
||||
};
|
||||
|
||||
#endif // EDITORRESOURCEPREVIEW_H
|
|
@ -448,6 +448,8 @@ void EditorSettings::_load_defaults() {
|
|||
set("text_editor/create_signal_callbacks",true);
|
||||
|
||||
set("file_dialog/show_hidden_files", false);
|
||||
set("file_dialog/thumbnail_size", 64);
|
||||
hints["file_dialog/thumbnail_size"]=PropertyInfo(Variant::INT,"file_dialog/thumbnail_size",PROPERTY_HINT_RANGE,"32,128,16");
|
||||
|
||||
set("animation/autorename_animation_tracks",true);
|
||||
set("animation/confirm_insert_track",true);
|
||||
|
|
BIN
tools/editor/icons/icon_wait_no_preview.png
Normal file
After Width: | Height: | Size: 1 KiB |
BIN
tools/editor/icons/icon_wait_preview_1.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_2.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_3.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_4.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_5.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_6.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_7.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
tools/editor/icons/icon_wait_preview_8.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
664
tools/editor/plugins/editor_preview_plugins.cpp
Normal file
|
@ -0,0 +1,664 @@
|
|||
#include "editor_preview_plugins.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "tools/editor/editor_settings.h"
|
||||
#include "io/file_access_memory.h"
|
||||
#include "os/os.h"
|
||||
#include "scene/resources/material.h"
|
||||
#include "scene/resources/sample.h"
|
||||
|
||||
bool EditorTexturePreviewPlugin::handles(const String& p_type) const {
|
||||
|
||||
return ObjectTypeDB::is_type(p_type,"ImageTexture");
|
||||
}
|
||||
|
||||
Ref<Texture> EditorTexturePreviewPlugin::generate(const RES& p_from) {
|
||||
|
||||
Ref<ImageTexture> tex =p_from;
|
||||
Image img = tex->get_data();
|
||||
if (img.empty())
|
||||
return Ref<Texture>();
|
||||
|
||||
img.clear_mipmaps();
|
||||
|
||||
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
|
||||
if (img.is_compressed()) {
|
||||
if (img.decompress()!=OK)
|
||||
return Ref<Texture>();
|
||||
} else if (img.get_format()!=Image::FORMAT_RGB && img.get_format()!=Image::FORMAT_RGB) {
|
||||
img.convert(Image::FORMAT_RGBA);
|
||||
}
|
||||
|
||||
int width,height;
|
||||
if (img.get_width() > thumbnail_size && img.get_width() >= img.get_height()) {
|
||||
|
||||
width=thumbnail_size;
|
||||
height = img.get_height() * thumbnail_size / img.get_width();
|
||||
} else if (img.get_height() > thumbnail_size && img.get_height() >= img.get_width()) {
|
||||
|
||||
height=thumbnail_size;
|
||||
width = img.get_width() * thumbnail_size / img.get_height();
|
||||
} else {
|
||||
|
||||
width=img.get_width();
|
||||
height=img.get_height();
|
||||
}
|
||||
|
||||
img.resize(width,height);
|
||||
|
||||
Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
|
||||
|
||||
ptex->create_from_image(img,0);
|
||||
return ptex;
|
||||
|
||||
}
|
||||
|
||||
EditorTexturePreviewPlugin::EditorTexturePreviewPlugin() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
Ref<Texture> EditorPackedScenePreviewPlugin::_gen_from_imd(Ref<ResourceImportMetadata> p_imd) {
|
||||
|
||||
if (p_imd.is_null())
|
||||
return Ref<Texture>();
|
||||
|
||||
if (!p_imd->has_option("thumbnail"))
|
||||
return Ref<Texture>();
|
||||
|
||||
Variant tn = p_imd->get_option("thumbnail");
|
||||
print_line(Variant::get_type_name(tn.get_type()));
|
||||
DVector<uint8_t> thumbnail = tn;
|
||||
|
||||
int len = thumbnail.size();
|
||||
if (len==0)
|
||||
return Ref<Texture>();
|
||||
|
||||
|
||||
DVector<uint8_t>::Read r = thumbnail.read();
|
||||
|
||||
Image img(r.ptr(),len);
|
||||
if (img.empty())
|
||||
return Ref<Texture>();
|
||||
|
||||
Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
|
||||
ptex->create_from_image(img,0);
|
||||
return ptex;
|
||||
|
||||
}
|
||||
|
||||
bool EditorPackedScenePreviewPlugin::handles(const String& p_type) const {
|
||||
|
||||
return ObjectTypeDB::is_type(p_type,"PackedScene");
|
||||
}
|
||||
Ref<Texture> EditorPackedScenePreviewPlugin::generate(const RES& p_from) {
|
||||
|
||||
Ref<ResourceImportMetadata> imd = p_from->get_import_metadata();
|
||||
return _gen_from_imd(imd);
|
||||
}
|
||||
|
||||
Ref<Texture> EditorPackedScenePreviewPlugin::generate_from_path(const String& p_path) {
|
||||
|
||||
Ref<ResourceImportMetadata> imd = ResourceLoader::load_import_metadata(p_path);
|
||||
return _gen_from_imd(imd);
|
||||
}
|
||||
|
||||
EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() {
|
||||
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
|
||||
bool EditorMaterialPreviewPlugin::handles(const String& p_type) const {
|
||||
|
||||
return ObjectTypeDB::is_type(p_type,"Material"); //any material
|
||||
}
|
||||
|
||||
Ref<Texture> EditorMaterialPreviewPlugin::generate(const RES& p_from) {
|
||||
|
||||
Ref<Material> material = p_from;
|
||||
ERR_FAIL_COND_V(material.is_null(),Ref<Texture>());
|
||||
|
||||
VS::get_singleton()->mesh_surface_set_material(sphere,0,material->get_rid());
|
||||
|
||||
VS::get_singleton()->viewport_queue_screen_capture(viewport);
|
||||
VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_ONCE); //once used for capture
|
||||
// print_line("queue capture!");
|
||||
Image img;
|
||||
|
||||
int timeout=1000;
|
||||
while(timeout) {
|
||||
//print_line("try capture?");
|
||||
OS::get_singleton()->delay_usec(10);
|
||||
img = VS::get_singleton()->viewport_get_screen_capture(viewport);
|
||||
if (!img.empty())
|
||||
break;
|
||||
timeout--;
|
||||
}
|
||||
|
||||
//print_line("captured!");
|
||||
VS::get_singleton()->mesh_surface_set_material(sphere,0,RID());
|
||||
|
||||
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
|
||||
img.resize(thumbnail_size,thumbnail_size);
|
||||
|
||||
Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture ));
|
||||
ptex->create_from_image(img,0);
|
||||
return ptex;
|
||||
}
|
||||
|
||||
EditorMaterialPreviewPlugin::EditorMaterialPreviewPlugin() {
|
||||
|
||||
scenario = VS::get_singleton()->scenario_create();
|
||||
|
||||
viewport = VS::get_singleton()->viewport_create();
|
||||
VS::get_singleton()->viewport_set_as_render_target(viewport,true);
|
||||
VS::get_singleton()->viewport_set_render_target_update_mode(viewport,VS::RENDER_TARGET_UPDATE_DISABLED);
|
||||
VS::get_singleton()->viewport_set_scenario(viewport,scenario);
|
||||
VS::ViewportRect vr;
|
||||
vr.x=0;
|
||||
vr.y=0;
|
||||
vr.width=128;
|
||||
vr.height=128;
|
||||
VS::get_singleton()->viewport_set_rect(viewport,vr);
|
||||
|
||||
camera = VS::get_singleton()->camera_create();
|
||||
VS::get_singleton()->viewport_attach_camera(viewport,camera);
|
||||
VS::get_singleton()->camera_set_transform(camera,Transform(Matrix3(),Vector3(0,0,3)));
|
||||
VS::get_singleton()->camera_set_perspective(camera,45,0.1,10);
|
||||
|
||||
light = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
|
||||
light_instance = VS::get_singleton()->instance_create2(light,scenario);
|
||||
VS::get_singleton()->instance_set_transform(light_instance,Transform().looking_at(Vector3(-1,-1,-1),Vector3(0,1,0)));
|
||||
|
||||
light2 = VS::get_singleton()->light_create(VS::LIGHT_DIRECTIONAL);
|
||||
VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_DIFFUSE,Color(0.7,0.7,0.7));
|
||||
VS::get_singleton()->light_set_color(light2,VS::LIGHT_COLOR_SPECULAR,Color(0.0,0.0,0.0));
|
||||
light_instance2 = VS::get_singleton()->instance_create2(light2,scenario);
|
||||
|
||||
VS::get_singleton()->instance_set_transform(light_instance2,Transform().looking_at(Vector3(0,1,0),Vector3(0,0,1)));
|
||||
|
||||
sphere = VS::get_singleton()->mesh_create();
|
||||
sphere_instance = VS::get_singleton()->instance_create2(sphere,scenario);
|
||||
|
||||
int lats=32;
|
||||
int lons=32;
|
||||
float radius=1.0;
|
||||
|
||||
DVector<Vector3> vertices;
|
||||
DVector<Vector3> normals;
|
||||
DVector<Vector2> uvs;
|
||||
DVector<float> tangents;
|
||||
Matrix3 tt = Matrix3(Vector3(0,1,0),Math_PI*0.5);
|
||||
|
||||
for(int i = 1; i <= lats; i++) {
|
||||
double lat0 = Math_PI * (-0.5 + (double) (i - 1) / lats);
|
||||
double z0 = Math::sin(lat0);
|
||||
double zr0 = Math::cos(lat0);
|
||||
|
||||
double lat1 = Math_PI * (-0.5 + (double) i / lats);
|
||||
double z1 = Math::sin(lat1);
|
||||
double zr1 = Math::cos(lat1);
|
||||
|
||||
for(int j = lons; j >= 1; j--) {
|
||||
|
||||
double lng0 = 2 * Math_PI * (double) (j - 1) / lons;
|
||||
double x0 = Math::cos(lng0);
|
||||
double y0 = Math::sin(lng0);
|
||||
|
||||
double lng1 = 2 * Math_PI * (double) (j) / lons;
|
||||
double x1 = Math::cos(lng1);
|
||||
double y1 = Math::sin(lng1);
|
||||
|
||||
|
||||
Vector3 v[4]={
|
||||
Vector3(x1 * zr0, z0, y1 *zr0),
|
||||
Vector3(x1 * zr1, z1, y1 *zr1),
|
||||
Vector3(x0 * zr1, z1, y0 *zr1),
|
||||
Vector3(x0 * zr0, z0, y0 *zr0)
|
||||
};
|
||||
|
||||
#define ADD_POINT(m_idx) \
|
||||
normals.push_back(v[m_idx]);\
|
||||
vertices.push_back(v[m_idx]*radius);\
|
||||
{ Vector2 uv(Math::atan2(v[m_idx].x,v[m_idx].z),Math::atan2(-v[m_idx].y,v[m_idx].z));\
|
||||
uv/=Math_PI;\
|
||||
uv*=4.0;\
|
||||
uv=uv*0.5+Vector2(0.5,0.5);\
|
||||
uvs.push_back(uv);\
|
||||
}\
|
||||
{ Vector3 t = tt.xform(v[m_idx]);\
|
||||
tangents.push_back(t.x);\
|
||||
tangents.push_back(t.y);\
|
||||
tangents.push_back(t.z);\
|
||||
tangents.push_back(1.0);\
|
||||
}
|
||||
|
||||
|
||||
|
||||
ADD_POINT(0);
|
||||
ADD_POINT(1);
|
||||
ADD_POINT(2);
|
||||
|
||||
ADD_POINT(2);
|
||||
ADD_POINT(3);
|
||||
ADD_POINT(0);
|
||||
}
|
||||
}
|
||||
|
||||
Array arr;
|
||||
arr.resize(VS::ARRAY_MAX);
|
||||
arr[VS::ARRAY_VERTEX]=vertices;
|
||||
arr[VS::ARRAY_NORMAL]=normals;
|
||||
arr[VS::ARRAY_TANGENT]=tangents;
|
||||
arr[VS::ARRAY_TEX_UV]=uvs;
|
||||
VS::get_singleton()->mesh_add_surface(sphere,VS::PRIMITIVE_TRIANGLES,arr);
|
||||
|
||||
}
|
||||
|
||||
EditorMaterialPreviewPlugin::~EditorMaterialPreviewPlugin() {
|
||||
|
||||
VS::get_singleton()->free(sphere);
|
||||
VS::get_singleton()->free(sphere_instance);
|
||||
VS::get_singleton()->free(viewport);
|
||||
VS::get_singleton()->free(light);
|
||||
VS::get_singleton()->free(light_instance);
|
||||
VS::get_singleton()->free(light2);
|
||||
VS::get_singleton()->free(light_instance2);
|
||||
VS::get_singleton()->free(camera);
|
||||
VS::get_singleton()->free(scenario);
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool _is_text_char(CharType c) {
|
||||
|
||||
return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_';
|
||||
}
|
||||
|
||||
bool EditorScriptPreviewPlugin::handles(const String& p_type) const {
|
||||
|
||||
return ObjectTypeDB::is_type(p_type,"Script");
|
||||
}
|
||||
|
||||
Ref<Texture> EditorScriptPreviewPlugin::generate(const RES& p_from) {
|
||||
|
||||
|
||||
Ref<Script> scr = p_from;
|
||||
if (scr.is_null())
|
||||
return Ref<Texture>();
|
||||
|
||||
String code = scr->get_source_code().strip_edges();
|
||||
if (code=="")
|
||||
return Ref<Texture>();
|
||||
|
||||
List<String> kwors;
|
||||
scr->get_language()->get_reserved_words(&kwors);
|
||||
|
||||
Set<String> keywords;
|
||||
|
||||
for(List<String>::Element *E=kwors.front();E;E=E->next()) {
|
||||
|
||||
keywords.insert(E->get());
|
||||
|
||||
}
|
||||
|
||||
|
||||
int line = 0;
|
||||
int col=0;
|
||||
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
|
||||
Image img(thumbnail_size,thumbnail_size,0,Image::FORMAT_RGBA);
|
||||
|
||||
|
||||
|
||||
Color bg_color = EditorSettings::get_singleton()->get("text_editor/background_color");
|
||||
bg_color.a=1.0;
|
||||
Color keyword_color = EditorSettings::get_singleton()->get("text_editor/keyword_color");
|
||||
Color text_color = EditorSettings::get_singleton()->get("text_editor/text_color");
|
||||
Color symbol_color = EditorSettings::get_singleton()->get("text_editor/symbol_color");
|
||||
Color comment_color = EditorSettings::get_singleton()->get("text_editor/comment_color");
|
||||
|
||||
|
||||
for(int i=0;i<thumbnail_size;i++) {
|
||||
for(int j=0;j<thumbnail_size;j++) {
|
||||
img.put_pixel(i,j,bg_color);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool prev_is_text=false;
|
||||
bool in_keyword=false;
|
||||
for(int i=0;i<code.length();i++) {
|
||||
|
||||
CharType c = code[i];
|
||||
if (c>32) {
|
||||
if (col<thumbnail_size) {
|
||||
Color color = text_color;
|
||||
|
||||
if (c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t')) {
|
||||
//make symbol a little visible
|
||||
color=symbol_color;
|
||||
in_keyword=false;
|
||||
} else if (!prev_is_text && _is_text_char(c)) {
|
||||
int pos = i;
|
||||
|
||||
while(_is_text_char(code[pos])) {
|
||||
pos++;
|
||||
}
|
||||
///print_line("from "+itos(i)+" to "+itos(pos));
|
||||
String word = code.substr(i,pos-i);
|
||||
//print_line("found word: "+word);
|
||||
if (keywords.has(word))
|
||||
in_keyword=true;
|
||||
|
||||
} else if (!_is_text_char(c)) {
|
||||
in_keyword=false;
|
||||
}
|
||||
|
||||
if (in_keyword)
|
||||
color=keyword_color;
|
||||
|
||||
Color ul=color;
|
||||
ul.a*=0.5;
|
||||
img.put_pixel(col,line*2,bg_color.blend(ul));
|
||||
img.put_pixel(col,line*2+1,color);
|
||||
|
||||
prev_is_text=_is_text_char(c);
|
||||
}
|
||||
} else {
|
||||
|
||||
prev_is_text=false;
|
||||
in_keyword=false;
|
||||
|
||||
if (c=='\n') {
|
||||
col=0;
|
||||
line++;
|
||||
if (line>=thumbnail_size/2)
|
||||
break;
|
||||
} else if (c=='\t') {
|
||||
col+=3;
|
||||
}
|
||||
}
|
||||
col++;
|
||||
}
|
||||
|
||||
Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
|
||||
|
||||
ptex->create_from_image(img,0);
|
||||
return ptex;
|
||||
|
||||
}
|
||||
|
||||
EditorScriptPreviewPlugin::EditorScriptPreviewPlugin() {
|
||||
|
||||
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////
|
||||
|
||||
bool EditorSamplePreviewPlugin::handles(const String& p_type) const {
|
||||
|
||||
return ObjectTypeDB::is_type(p_type,"Sample");
|
||||
}
|
||||
|
||||
Ref<Texture> EditorSamplePreviewPlugin::generate(const RES& p_from) {
|
||||
|
||||
Ref<Sample> smp =p_from;
|
||||
ERR_FAIL_COND_V(smp.is_null(),Ref<Texture>());
|
||||
|
||||
|
||||
int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size");
|
||||
|
||||
DVector<uint8_t> img;
|
||||
int w = thumbnail_size;
|
||||
int h = thumbnail_size;
|
||||
img.resize(w*h*3);
|
||||
|
||||
DVector<uint8_t>::Write imgdata = img.write();
|
||||
uint8_t * imgw = imgdata.ptr();
|
||||
DVector<uint8_t> data = smp->get_data();
|
||||
DVector<uint8_t>::Read sampledata = data.read();
|
||||
const uint8_t *sdata=sampledata.ptr();
|
||||
|
||||
bool stereo = smp->is_stereo();
|
||||
bool _16=smp->get_format()==Sample::FORMAT_PCM16;
|
||||
int len = smp->get_length();
|
||||
|
||||
if (len<1)
|
||||
return Ref<Texture>();
|
||||
|
||||
if (smp->get_format()==Sample::FORMAT_IMA_ADPCM) {
|
||||
|
||||
struct IMA_ADPCM_State {
|
||||
|
||||
int16_t step_index;
|
||||
int32_t predictor;
|
||||
/* values at loop point */
|
||||
int16_t loop_step_index;
|
||||
int32_t loop_predictor;
|
||||
int32_t last_nibble;
|
||||
int32_t loop_pos;
|
||||
int32_t window_ofs;
|
||||
const uint8_t *ptr;
|
||||
} ima_adpcm;
|
||||
|
||||
ima_adpcm.step_index=0;
|
||||
ima_adpcm.predictor=0;
|
||||
ima_adpcm.loop_step_index=0;
|
||||
ima_adpcm.loop_predictor=0;
|
||||
ima_adpcm.last_nibble=-1;
|
||||
ima_adpcm.loop_pos=0x7FFFFFFF;
|
||||
ima_adpcm.window_ofs=0;
|
||||
ima_adpcm.ptr=NULL;
|
||||
|
||||
|
||||
for(int i=0;i<w;i++) {
|
||||
|
||||
float max[2]={-1e10,-1e10};
|
||||
float min[2]={1e10,1e10};
|
||||
int from = i*len/w;
|
||||
int to = (i+1)*len/w;
|
||||
if (to>=len)
|
||||
to=len-1;
|
||||
|
||||
for(int j=from;j<to;j++) {
|
||||
|
||||
while(j>ima_adpcm.last_nibble) {
|
||||
|
||||
static const int16_t _ima_adpcm_step_table[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
static const int8_t _ima_adpcm_index_table[16] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
int16_t nibble,signed_nibble,diff,step;
|
||||
|
||||
ima_adpcm.last_nibble++;
|
||||
const uint8_t *src_ptr=sdata;
|
||||
|
||||
nibble = (ima_adpcm.last_nibble&1)?
|
||||
(src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
|
||||
step=_ima_adpcm_step_table[ima_adpcm.step_index];
|
||||
|
||||
ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
|
||||
if (ima_adpcm.step_index<0)
|
||||
ima_adpcm.step_index=0;
|
||||
if (ima_adpcm.step_index>88)
|
||||
ima_adpcm.step_index=88;
|
||||
|
||||
/*
|
||||
signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
|
||||
diff = (2 * signed_nibble + 1) * step / 4; */
|
||||
|
||||
diff = step >> 3 ;
|
||||
if (nibble & 1)
|
||||
diff += step >> 2 ;
|
||||
if (nibble & 2)
|
||||
diff += step >> 1 ;
|
||||
if (nibble & 4)
|
||||
diff += step ;
|
||||
if (nibble & 8)
|
||||
diff = -diff ;
|
||||
|
||||
ima_adpcm.predictor+=diff;
|
||||
if (ima_adpcm.predictor<-0x8000)
|
||||
ima_adpcm.predictor=-0x8000;
|
||||
else if (ima_adpcm.predictor>0x7FFF)
|
||||
ima_adpcm.predictor=0x7FFF;
|
||||
|
||||
|
||||
/* store loop if there */
|
||||
if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
|
||||
|
||||
ima_adpcm.loop_step_index = ima_adpcm.step_index;
|
||||
ima_adpcm.loop_predictor = ima_adpcm.predictor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float v=ima_adpcm.predictor/32767.0;
|
||||
if (v>max[0])
|
||||
max[0]=v;
|
||||
if (v<min[0])
|
||||
min[0]=v;
|
||||
}
|
||||
max[0]*=0.8;
|
||||
min[0]*=0.8;
|
||||
|
||||
for(int j=0;j<h;j++) {
|
||||
float v = (j/(float)h) * 2.0 - 1.0;
|
||||
uint8_t* imgofs = &imgw[(j*w+i)*3];
|
||||
if (v>min[0] && v<max[0]) {
|
||||
imgofs[0]=255;
|
||||
imgofs[1]=150;
|
||||
imgofs[2]=80;
|
||||
} else {
|
||||
imgofs[0]=0;
|
||||
imgofs[1]=0;
|
||||
imgofs[2]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i=0;i<w;i++) {
|
||||
// i trust gcc will optimize this loop
|
||||
float max[2]={-1e10,-1e10};
|
||||
float min[2]={1e10,1e10};
|
||||
int c=stereo?2:1;
|
||||
int from = i*len/w;
|
||||
int to = (i+1)*len/w;
|
||||
if (to>=len)
|
||||
to=len-1;
|
||||
|
||||
if (_16) {
|
||||
const int16_t*src =(const int16_t*)sdata;
|
||||
|
||||
for(int j=0;j<c;j++) {
|
||||
|
||||
for(int k=from;k<=to;k++) {
|
||||
|
||||
float v = src[k*c+j]/32768.0;
|
||||
if (v>max[j])
|
||||
max[j]=v;
|
||||
if (v<min[j])
|
||||
min[j]=v;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
const int8_t*src =(const int8_t*)sdata;
|
||||
|
||||
for(int j=0;j<c;j++) {
|
||||
|
||||
for(int k=from;k<=to;k++) {
|
||||
|
||||
float v = src[k*c+j]/128.0;
|
||||
if (v>max[j])
|
||||
max[j]=v;
|
||||
if (v<min[j])
|
||||
min[j]=v;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
max[0]*=0.8;
|
||||
max[1]*=0.8;
|
||||
min[0]*=0.8;
|
||||
min[1]*=0.8;
|
||||
|
||||
if (!stereo) {
|
||||
for(int j=0;j<h;j++) {
|
||||
float v = (j/(float)h) * 2.0 - 1.0;
|
||||
uint8_t* imgofs = &imgw[(j*w+i)*3];
|
||||
if (v>min[0] && v<max[0]) {
|
||||
imgofs[0]=255;
|
||||
imgofs[1]=150;
|
||||
imgofs[2]=80;
|
||||
} else {
|
||||
imgofs[0]=0;
|
||||
imgofs[1]=0;
|
||||
imgofs[2]=0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
for(int j=0;j<h;j++) {
|
||||
|
||||
int half,ofs;
|
||||
float v;
|
||||
if (j<(h/2)) {
|
||||
half=0;
|
||||
ofs=0;
|
||||
v = (j/(float)(h/2)) * 2.0 - 1.0;
|
||||
} else {
|
||||
half=1;
|
||||
ofs=h/2;
|
||||
v = ((j-(h/2))/(float)(h/2)) * 2.0 - 1.0;
|
||||
}
|
||||
|
||||
uint8_t* imgofs = &imgw[(j*w+i)*3];
|
||||
if (v>min[half] && v<max[half]) {
|
||||
imgofs[0]=255;
|
||||
imgofs[1]=150;
|
||||
imgofs[2]=80;
|
||||
} else {
|
||||
imgofs[0]=0;
|
||||
imgofs[1]=0;
|
||||
imgofs[2]=0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
imgdata = DVector<uint8_t>::Write();
|
||||
|
||||
Ref<ImageTexture> ptex = Ref<ImageTexture>( memnew( ImageTexture));
|
||||
ptex->create_from_image(Image(w,h,0,Image::FORMAT_RGB,img),0);
|
||||
return ptex;
|
||||
|
||||
}
|
||||
|
||||
EditorSamplePreviewPlugin::EditorSamplePreviewPlugin() {
|
||||
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
69
tools/editor/plugins/editor_preview_plugins.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef EDITORPREVIEWPLUGINS_H
|
||||
#define EDITORPREVIEWPLUGINS_H
|
||||
|
||||
#include "tools/editor/editor_resource_preview.h"
|
||||
|
||||
class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
public:
|
||||
|
||||
virtual bool handles(const String& p_type) const;
|
||||
virtual Ref<Texture> generate(const RES& p_from);
|
||||
|
||||
EditorTexturePreviewPlugin();
|
||||
};
|
||||
|
||||
|
||||
class EditorPackedScenePreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
|
||||
Ref<Texture> _gen_from_imd(Ref<ResourceImportMetadata> p_imd);
|
||||
public:
|
||||
|
||||
virtual bool handles(const String& p_type) const;
|
||||
virtual Ref<Texture> generate(const RES& p_from);
|
||||
virtual Ref<Texture> generate_from_path(const String& p_path);
|
||||
|
||||
EditorPackedScenePreviewPlugin();
|
||||
};
|
||||
|
||||
class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
|
||||
RID scenario;
|
||||
RID sphere;
|
||||
RID sphere_instance;
|
||||
RID viewport;
|
||||
RID light;
|
||||
RID light_instance;
|
||||
RID light2;
|
||||
RID light_instance2;
|
||||
RID camera;
|
||||
public:
|
||||
|
||||
virtual bool handles(const String& p_type) const;
|
||||
virtual Ref<Texture> generate(const RES& p_from);
|
||||
|
||||
EditorMaterialPreviewPlugin();
|
||||
~EditorMaterialPreviewPlugin();
|
||||
};
|
||||
|
||||
class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
public:
|
||||
|
||||
virtual bool handles(const String& p_type) const;
|
||||
virtual Ref<Texture> generate(const RES& p_from);
|
||||
|
||||
EditorScriptPreviewPlugin();
|
||||
};
|
||||
|
||||
|
||||
class EditorSamplePreviewPlugin : public EditorResourcePreviewGenerator {
|
||||
public:
|
||||
|
||||
virtual bool handles(const String& p_type) const;
|
||||
virtual Ref<Texture> generate(const RES& p_from);
|
||||
|
||||
EditorSamplePreviewPlugin();
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // EDITORPREVIEWPLUGINS_H
|
|
@ -98,6 +98,125 @@ void SampleEditor::generate_preview_texture(const Ref<Sample>& p_sample,Ref<Imag
|
|||
if (p_sample->get_format()==Sample::FORMAT_IMA_ADPCM) {
|
||||
|
||||
|
||||
struct IMA_ADPCM_State {
|
||||
|
||||
int16_t step_index;
|
||||
int32_t predictor;
|
||||
/* values at loop point */
|
||||
int16_t loop_step_index;
|
||||
int32_t loop_predictor;
|
||||
int32_t last_nibble;
|
||||
int32_t loop_pos;
|
||||
int32_t window_ofs;
|
||||
const uint8_t *ptr;
|
||||
} ima_adpcm;
|
||||
|
||||
ima_adpcm.step_index=0;
|
||||
ima_adpcm.predictor=0;
|
||||
ima_adpcm.loop_step_index=0;
|
||||
ima_adpcm.loop_predictor=0;
|
||||
ima_adpcm.last_nibble=-1;
|
||||
ima_adpcm.loop_pos=0x7FFFFFFF;
|
||||
ima_adpcm.window_ofs=0;
|
||||
ima_adpcm.ptr=NULL;
|
||||
|
||||
|
||||
for(int i=0;i<w;i++) {
|
||||
|
||||
float max[2]={-1e10,-1e10};
|
||||
float min[2]={1e10,1e10};
|
||||
int from = i*len/w;
|
||||
int to = (i+1)*len/w;
|
||||
if (to>=len)
|
||||
to=len-1;
|
||||
|
||||
for(int j=from;j<to;j++) {
|
||||
|
||||
while(j>ima_adpcm.last_nibble) {
|
||||
|
||||
static const int16_t _ima_adpcm_step_table[89] = {
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
|
||||
19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
|
||||
50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
|
||||
130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
|
||||
337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
|
||||
876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
|
||||
2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
|
||||
5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
|
||||
15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
|
||||
};
|
||||
|
||||
static const int8_t _ima_adpcm_index_table[16] = {
|
||||
-1, -1, -1, -1, 2, 4, 6, 8,
|
||||
-1, -1, -1, -1, 2, 4, 6, 8
|
||||
};
|
||||
|
||||
int16_t nibble,signed_nibble,diff,step;
|
||||
|
||||
ima_adpcm.last_nibble++;
|
||||
const uint8_t *src_ptr=sdata;
|
||||
|
||||
nibble = (ima_adpcm.last_nibble&1)?
|
||||
(src_ptr[ima_adpcm.last_nibble>>1]>>4):(src_ptr[ima_adpcm.last_nibble>>1]&0xF);
|
||||
step=_ima_adpcm_step_table[ima_adpcm.step_index];
|
||||
|
||||
ima_adpcm.step_index += _ima_adpcm_index_table[nibble];
|
||||
if (ima_adpcm.step_index<0)
|
||||
ima_adpcm.step_index=0;
|
||||
if (ima_adpcm.step_index>88)
|
||||
ima_adpcm.step_index=88;
|
||||
|
||||
/*
|
||||
signed_nibble = (nibble&7) * ((nibble&8)?-1:1);
|
||||
diff = (2 * signed_nibble + 1) * step / 4; */
|
||||
|
||||
diff = step >> 3 ;
|
||||
if (nibble & 1)
|
||||
diff += step >> 2 ;
|
||||
if (nibble & 2)
|
||||
diff += step >> 1 ;
|
||||
if (nibble & 4)
|
||||
diff += step ;
|
||||
if (nibble & 8)
|
||||
diff = -diff ;
|
||||
|
||||
ima_adpcm.predictor+=diff;
|
||||
if (ima_adpcm.predictor<-0x8000)
|
||||
ima_adpcm.predictor=-0x8000;
|
||||
else if (ima_adpcm.predictor>0x7FFF)
|
||||
ima_adpcm.predictor=0x7FFF;
|
||||
|
||||
|
||||
/* store loop if there */
|
||||
if (ima_adpcm.last_nibble==ima_adpcm.loop_pos) {
|
||||
|
||||
ima_adpcm.loop_step_index = ima_adpcm.step_index;
|
||||
ima_adpcm.loop_predictor = ima_adpcm.predictor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
float v=ima_adpcm.predictor/32767.0;
|
||||
if (v>max[0])
|
||||
max[0]=v;
|
||||
if (v<min[0])
|
||||
min[0]=v;
|
||||
}
|
||||
|
||||
for(int j=0;j<h;j++) {
|
||||
float v = (j/(float)h) * 2.0 - 1.0;
|
||||
uint8_t* imgofs = &imgw[(j*w+i)*3];
|
||||
if (v>min[0] && v<max[0]) {
|
||||
imgofs[0]=255;
|
||||
imgofs[1]=150;
|
||||
imgofs[2]=80;
|
||||
} else {
|
||||
imgofs[0]=0;
|
||||
imgofs[1]=0;
|
||||
imgofs[2]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i=0;i<w;i++) {
|
||||
// i trust gcc will optimize this loop
|
||||
|
|
|
@ -239,7 +239,7 @@ public:
|
|||
void set_state(const Dictionary& p_state);
|
||||
Dictionary get_state() const;
|
||||
void reset();
|
||||
|
||||
Viewport *get_viewport_node() { return viewport; }
|
||||
|
||||
|
||||
SpatialEditorViewport(SpatialEditor *p_spatial_editor,EditorNode *p_editor,int p_index);
|
||||
|
@ -422,6 +422,7 @@ private:
|
|||
HBoxContainer *hbc_menu;
|
||||
|
||||
|
||||
|
||||
//
|
||||
//
|
||||
void _generate_selection_box();
|
||||
|
@ -514,6 +515,11 @@ public:
|
|||
|
||||
void set_can_preview(Camera* p_preview);
|
||||
|
||||
SpatialEditorViewport *get_editor_viewport(int p_idx) {
|
||||
ERR_FAIL_INDEX_V(p_idx,4,NULL);
|
||||
return viewports[p_idx];
|
||||
}
|
||||
|
||||
Camera *get_camera() { return NULL; }
|
||||
void edit(Spatial *p_spatial);
|
||||
void clear();
|
||||
|
|
|
@ -152,7 +152,7 @@ void ResourcesDock::save_resource_as(const Ref<Resource>& p_resource) {
|
|||
|
||||
List<String> extensions;
|
||||
ResourceSaver::get_recognized_extensions(res,&extensions);
|
||||
file->set_mode(FileDialog::MODE_SAVE_FILE);
|
||||
file->set_mode(EditorFileDialog::MODE_SAVE_FILE);
|
||||
|
||||
if (p_resource->get_path()!="" && p_resource->get_path().find("::")==-1) {
|
||||
|
||||
|
@ -396,7 +396,7 @@ ResourcesDock::ResourcesDock(EditorNode *p_editor) {
|
|||
accept = memnew (AcceptDialog);
|
||||
add_child(accept);
|
||||
|
||||
file = memnew( FileDialog );
|
||||
file = memnew( EditorFileDialog );
|
||||
add_child(file);
|
||||
file->connect("file_selected",this,"_file_action");
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "scene/gui/menu_button.h"
|
||||
#include "scene/gui/file_dialog.h"
|
||||
#include "create_dialog.h"
|
||||
#include "editor_file_dialog.h"
|
||||
|
||||
|
||||
class EditorNode;
|
||||
|
@ -68,7 +69,7 @@ class ResourcesDock : public VBoxContainer {
|
|||
CreateDialog *create_dialog;
|
||||
|
||||
AcceptDialog *accept;
|
||||
FileDialog *file;
|
||||
EditorFileDialog *file;
|
||||
Tree *resources;
|
||||
bool block_add;
|
||||
int current_action;
|
||||
|
|