diff --git a/Application/src/commons/common/gui/FileChooser.cpp b/Application/src/commons/common/gui/FileChooser.cpp index 8a769c1183946f6f6a80e2515e051d049d0ed96a..1ba01818f61351110667f362807e62bcde66a1c8 100644 --- a/Application/src/commons/common/gui/FileChooser.cpp +++ b/Application/src/commons/common/gui/FileChooser.cpp @@ -119,7 +119,7 @@ FileChooser::FileChooser(const file::Path& start, const std::string& extension, _columns->set_name("Columns"); _rows->set_name("Rows"); - if(_current_tab.content) + if(_current_tab.content && !_selected_file.empty()) _columns->set_children({_rows, _current_tab.content}); else _columns->set_children({_rows}); @@ -164,10 +164,6 @@ FileChooser::FileChooser(const file::Path& start, const std::string& extension, }); } -void FileChooser::set_on_update(std::function<void (DrawStructure &)> && fn) { - _on_update = std::move(fn); -} - void FileChooser::set_tabs(const std::vector<Settings>& tabs) { _tabs.clear(); tabs_elements.clear(); @@ -215,17 +211,24 @@ void FileChooser::set_tabs(const std::vector<Settings>& tabs) { void FileChooser::set_tab(std::string tab) { if(tab != _current_tab.name) { - } else return; if(tab.empty()) { _current_tab = _default_tab; + + if(_on_tab_change) + _on_tab_change(_current_tab.name); + file_selected(0, ""); + } else if(!_tabs.count(tab)) { auto str = Meta::toStr(_tabs); Except("FileChooser %S does not contain tab '%S'.", &str, &tab); } else { _current_tab = _tabs.at(tab); + if(_on_tab_change) + _on_tab_change(_current_tab.name); + file_selected(0, ""); } for(auto &ptr : tabs_elements) { @@ -245,6 +248,7 @@ void FileChooser::set_tab(std::string tab) { _current_tab.content->set_name("Extra"); } + update_size(); _graph->set_dirty(&_base); } @@ -321,32 +325,48 @@ void FileChooser::change_folder(const file::Path& p) { } void FileChooser::file_selected(size_t, file::Path p) { - if(p.str() == ".." || p.is_folder()) { + if(!p.empty() && (p.str() == ".." || p.is_folder())) { change_folder(p); + } else { _selected_file = p; - if(!_selected_text) - _selected_text = std::make_shared<StaticText>("Selected: "+_selected_file.str(), Vec2(), Vec2(700, 0), Font(0.6)); - else - _selected_text->set_txt("Selected: "+_selected_file.str()); - - if(_tabs_bar) - _overall->set_children({ - _tabs_bar, - _columns, - _selected_text, - _button - }); - else - _overall->set_children({ - _columns, - _selected_text, - _button - }); + if(p.empty()) { + _selected_file = file::Path(); + _selected_text = nullptr; + if(_tabs_bar) + _overall->set_children({ + _tabs_bar, + _columns + }); + else + _overall->set_children({ + _columns + }); + + } else { + if(!_selected_text) + _selected_text = std::make_shared<StaticText>("Selected: "+_selected_file.str(), Vec2(), Vec2(700, 0), Font(0.6)); + else + _selected_text->set_txt("Selected: "+_selected_file.str()); + + if(_tabs_bar) + _overall->set_children({ + _tabs_bar, + _columns, + _selected_text, + _button + }); + else + _overall->set_children({ + _columns, + _selected_text, + _button + }); + } _overall->update_layout(); //update_size(); - if(_on_select_callback) + if(!_selected_file.empty() && _on_select_callback) _on_select_callback(_selected_file, _current_tab.extension); update_size(); } @@ -355,16 +375,16 @@ void FileChooser::file_selected(size_t, file::Path p) { } void FileChooser::update_size() { - float left_column_width = _graph->width() - 20 - (_current_tab.content && _current_tab.content->width() > 20 ? _current_tab.content->width() + 10 : 0) - 10; - if(_selected_text) { + float left_column_width = _graph->width() - 20 - (_current_tab.content && _current_tab.content->width() > 20 && !_selected_file.empty() ? _current_tab.content->width() + 10 : 0) - 10; + if(_selected_text && !_selected_file.empty()) { _selected_text->set_max_size(Size2(_graph->width() - 20)); } if(_tabs_bar) _tabs_bar->auto_size(Margin{0,0}); if(_tabs_bar) _tabs_bar->update_layout(); - float left_column_height = _graph->height() - 70 - 10 - (!_selected_file.empty() ? _button->height() + 10 : 0) - (_tabs_bar ? _tabs_bar->height() + 10 : 0) - (_selected_text && !_selected_file.empty() ? _selected_text->height() : 0); - _list->set_bounds(Bounds(0, 0, left_column_width, left_column_height - 70)); + float left_column_height = _graph->height() - 70 - 10 - (_selected_text && !_selected_file.empty() ? _button->height() + 65 : 0) - (_tabs_bar ? _tabs_bar->height() + 10 : 0) - 25; + _list->set_bounds(Bounds(0, 0, left_column_width, left_column_height)); _textfield->set_bounds(Bounds(0, 0, left_column_width, 30)); _button->set_bounds(Bounds(_list->pos() + Vec2(0, left_column_height), Size2(100, 30))); @@ -372,7 +392,7 @@ void FileChooser::update_size() { if(_rows) _rows->auto_size(Margin{0,0}); if(_rows) _rows->update_layout(); - if(_current_tab.content) + if(_current_tab.content && !_selected_file.empty()) _columns->set_children({_rows, _current_tab.content}); else _columns->set_children({_rows}); diff --git a/Application/src/commons/common/gui/FileChooser.h b/Application/src/commons/common/gui/FileChooser.h index f67bd3002fb4ec6b56a71265cc58081a625bd79c..4310e21cda5ab806899b78b80d74802b453edea9 100644 --- a/Application/src/commons/common/gui/FileChooser.h +++ b/Application/src/commons/common/gui/FileChooser.h @@ -66,6 +66,7 @@ protected: std::function<void(DrawStructure&)> _on_update; std::function<bool(file::Path)> _validity; std::function<void(file::Path)> _on_open; + std::function<void(std::string)> _on_tab_change; std::queue<std::function<void()>> _execute; std::mutex _execute_mutex; std::map<std::string, Settings> _tabs; @@ -82,8 +83,9 @@ public: void open(); void execute(std::function<void()>&&); void update_size(); - void set_on_update(std::function<void(DrawStructure&)>&&); - void set_on_open(std::function<void(file::Path)>&& fn) { _on_open = std::move(fn); } + void on_update(std::function<void(DrawStructure&)>&& fn) { _on_update = std::move(fn); } + void on_open(std::function<void(file::Path)>&& fn) { _on_open = std::move(fn); } + void on_tab_change(std::function<void(std::string)>&& fn) { _on_tab_change = std::move(fn); } void set_validity_check(std::function<bool(file::Path)>&& fn) { _validity = std::move(fn); } private: diff --git a/Application/src/commons/common/gui/types/Checkbox.h b/Application/src/commons/common/gui/types/Checkbox.h index 56a5c0ab1ce477c38ae3771a2f5481469384120b..d265a0d3e6eb8e6b8b8a15fdf3d2a8f837e4212c 100644 --- a/Application/src/commons/common/gui/types/Checkbox.h +++ b/Application/src/commons/common/gui/types/Checkbox.h @@ -21,7 +21,7 @@ protected: public: Checkbox(const Vec2& pos, const std::string& text = "", bool checked = false, const Font& font = Font(0.75)); - void set_callback(const decltype(_callback)& callback) { + void on_change(const decltype(_callback)& callback) { _callback = callback; } diff --git a/Application/src/commons/common/gui/types/Textfield.h b/Application/src/commons/common/gui/types/Textfield.h index d169e729298ece92773eea6c1ba0ebd7a37c4fe9..94c99ecfe1b88aeeb48c7b0f57cee95af0ef3b86 100644 --- a/Application/src/commons/common/gui/types/Textfield.h +++ b/Application/src/commons/common/gui/types/Textfield.h @@ -50,6 +50,8 @@ namespace gui { _font = font; _text_display.set_font(font); + if(_placeholder) + _placeholder->set_font(font); set_content_changed(true); } diff --git a/Application/src/commons/common/misc/metastring.h b/Application/src/commons/common/misc/metastring.h index eb7db578b6fdcebad85f54018e41761062a331cb..51d9052cdf49ecd0a95c44092ac5a1d278650c6e 100644 --- a/Application/src/commons/common/misc/metastring.h +++ b/Application/src/commons/common/misc/metastring.h @@ -71,6 +71,31 @@ namespace cmn { return ss.str(); } + std::string to_html() const { + static constexpr std::array<cmn::string_view, 5> names{{"us", "ms", "s", "min", "h"}}; + static constexpr std::array<double, 5> ratios{{1000, 1000, 60, 60, 24}}; + + double scaled = timestamp, previous_scaled = 0; + size_t i = 0; + while(i < ratios.size()-1 && scaled >= ratios[i]) { + scaled /= ratios[i]; + + previous_scaled = scaled - size_t(scaled); + previous_scaled *= ratios[i]; + + i++; + } + + size_t sub_part = (size_t)previous_scaled; + + std::stringstream ss; + ss << "<nr>" << std::fixed << std::setprecision(0) << scaled << "</nr>"; + if(i>0 && i > 2) + ss << ":<nr>" << std::setfill('0') << std::setw(2) << sub_part << "</nr>"; + ss << std::string(names[i].begin(), names[i].end()); + return ss.str(); + } + static DurationUS fromStr(const std::string&) { U_EXCEPTION("Not implemented."); return DurationUS{0}; diff --git a/Application/src/tracker/VideoOpener.cpp b/Application/src/tracker/VideoOpener.cpp index 5f732c47fc33167162f3762f1f97d8db716b6e33..8ee50e61b73952bc40a3c4772e7e6b7ddbb9c62e 100644 --- a/Application/src/tracker/VideoOpener.cpp +++ b/Application/src/tracker/VideoOpener.cpp @@ -15,12 +15,33 @@ namespace gui { GlobalSettings::docs_map_t temp_docs; sprite::Map temp_settings; +VideoOpener::LabeledCheckbox::LabeledCheckbox(const std::string& name) + : LabeledField(name), + _checkbox(std::make_shared<gui::Checkbox>(Vec2(), name)), + _ref(gui::temp_settings[name]) +{ + _checkbox->set_checked(_ref.value<bool>()); + _checkbox->set_font(Font(0.6)); + + _checkbox->on_change([this](){ + try { + _ref.get() = _checkbox->checked(); + + } catch(...) {} + }); +} + +void VideoOpener::LabeledCheckbox::update() { + _checkbox->set_checked(_ref.value<bool>()); +} + VideoOpener::LabeledTextField::LabeledTextField(const std::string& name) : LabeledField(name), - _text_field(std::make_shared<gui::Textfield>("", Bounds(0, 0, 300, 33))), + _text_field(std::make_shared<gui::Textfield>("", Bounds(0, 0, 300, 28))), _ref(gui::temp_settings[name]) { _text_field->set_placeholder(name); + _text_field->set_font(Font(0.6)); _text_field->set_text(_ref.get().valueString()); _text_field->on_text_changed([this](){ @@ -37,9 +58,10 @@ void VideoOpener::LabeledTextField::update() { VideoOpener::LabeledDropDown::LabeledDropDown(const std::string& name) : LabeledField(name), - _dropdown(std::make_shared<gui::Dropdown>(Bounds(0, 0, 300, 33))), + _dropdown(std::make_shared<gui::Dropdown>(Bounds(0, 0, 300, 28))), _ref(gui::temp_settings[name]) { + _dropdown->textfield()->set_font(Font(0.6)); assert(_ref.get().is_enum()); std::vector<Dropdown::TextItem> items; int index = 0; @@ -79,6 +101,7 @@ VideoOpener::VideoOpener() { TEMP_SETTING(output_name) = file::Path("video"); _horizontal_raw = std::make_shared<gui::HorizontalLayout>(); + _horizontal_raw->set_clickable(true); _raw_settings = std::make_shared<gui::VerticalLayout>(); _raw_info = std::make_shared<gui::VerticalLayout>(); _raw_info->set_policy(gui::VerticalLayout::LEFT); @@ -101,14 +124,16 @@ VideoOpener::VideoOpener() { _text_fields["average_samples"] = std::make_unique<LabeledTextField>("average_samples"); _text_fields["averaging_method"] = std::make_unique<LabeledDropDown>("averaging_method"); - std::vector<Layout::Ptr> objects{}; + std::vector<Layout::Ptr> objects{ + Layout::Ptr(std::make_shared<Text>("Settings", Vec2(), White, gui::Font(0.8, Style::Bold))) + }; for(auto &[key, ptr] : _text_fields) ptr->add_to(objects); _raw_settings->set_children(objects); - _raw_description = std::make_shared<gui::StaticText>("Info", Vec2(), Size2(500, -1)); - _raw_info->set_children({_screenshot, _raw_description}); + _raw_description = std::make_shared<gui::StaticText>("Info", Vec2(), Size2(400, -1), Font(0.6)); + _raw_info->set_children({Layout::Ptr(std::make_shared<Text>("Preview", Vec2(), White, gui::Font(0.8, Style::Bold))), _screenshot, _raw_description}); _horizontal_raw->set_children({_raw_settings, _raw_info}); _horizontal_raw->set_policy(gui::HorizontalLayout::TOP); @@ -200,14 +225,16 @@ VideoOpener::VideoOpener() { } - }, [this](auto& path, std::string tab){ select_file(path); }); + }, [this](auto& path, std::string tab) { + select_file(path); + }); _file_chooser->set_tabs({ FileChooser::Settings{std::string("Pre-processed (PV)"), std::string("pv"), _horizontal}, FileChooser::Settings{std::string("Convert (RAW)"), std::string("mp4;avi;mov;flv;m4v;webm"), _horizontal_raw} }); - _file_chooser->set_on_update([this](auto&) mutable { + _file_chooser->on_update([this](auto&) mutable { std::lock_guard guard(_video_mutex); if(_buffer) { auto image = _buffer->next(); @@ -237,7 +264,11 @@ VideoOpener::VideoOpener() { return false; }); - _file_chooser->set_on_open([this](auto){ + _file_chooser->on_open([this](auto){ + _buffer = nullptr; + }); + + _file_chooser->on_tab_change([this](auto){ _buffer = nullptr; }); @@ -403,9 +434,12 @@ std::unique_ptr<Image> VideoOpener::BufferedVideo::next() { void VideoOpener::select_file(const file::Path &p) { const double max_width = 500; + std::lock_guard guard(_file_chooser->graph()->lock()); - if(!p.empty() && (!p.has_extension() || p.extension() != "pv")) { + if(_file_chooser->current_tab().extension != "pv") { try { + if(p.empty()) + U_EXCEPTION("No file selected."); Debug("Opening '%S'", &p.str()); std::lock_guard guard(_video_mutex); @@ -443,6 +477,17 @@ void VideoOpener::select_file(const file::Path &p) { Except("Converting number: '%s'", e.what()); } + { + std::string info_text = "<h3>Info</h3>\n"; + info_text += "<key>resolution</key>: <ref><nr>"+Meta::toStr(_buffer->_video->size().width)+"</nr>x<nr>"+Meta::toStr(_buffer->_video->size().height)+"</nr></ref>\n"; + + DurationUS us{ uint64_t( _buffer->_video->length() / double(_buffer->_video->framerate()) * 1000.0 * 1000.0 ) }; + auto len = us.to_html(); + info_text += "<key>length</key>: <ref>"+len+"</ref>"; + + _raw_description->set_txt(info_text); + } + auto ratio = max_width / _screenshot->size().max(); Debug("%f (%f / %f)", ratio, max_width, _screenshot->size().max()); _screenshot->set_scale(Vec2(ratio)); @@ -452,6 +497,7 @@ void VideoOpener::select_file(const file::Path &p) { _horizontal_raw->auto_size(Margin{0, 0}); } catch(const std::exception& e) { + std::lock_guard guard(_video_mutex); Except("Cannot open file '%S' (%s)", &p.str(), e.what()); cv::Mat img = cv::Mat::zeros(max_width, max_width, CV_8UC1); @@ -503,6 +549,7 @@ void VideoOpener::select_file(const file::Path &p) { std::vector<Layout::Ptr> children { Layout::Ptr(std::make_shared<Text>("Settings", Vec2(), White, gui::Font(0.8, Style::Bold))) }; + for(auto &name : _settings_to_show) { std::string start; if(tmp[name].is_type<std::string>()) @@ -511,7 +558,7 @@ void VideoOpener::select_file(const file::Path &p) { start = tmp[name].get().valueString(); if(tmp[name].is_type<bool>()) { - children.push_back( Layout::Ptr(std::make_shared<Checkbox>(Vec2(), name, tmp[name].get().value<bool>(), gui::Font(0.7, Style::Bold))) ); + children.push_back( Layout::Ptr(std::make_shared<Checkbox>(Vec2(), name, tmp[name].get().value<bool>(), gui::Font(0.6))) ); } else if(name == "output_prefix") { std::vector<std::string> folders; for(auto &p : _selected.remove_filename().find_files()) { @@ -526,12 +573,14 @@ void VideoOpener::select_file(const file::Path &p) { } } - children.push_back( Layout::Ptr(std::make_shared<Text>(name, Vec2(), White, gui::Font(0.7, Style::Bold))) ); - children.push_back( Layout::Ptr(std::make_shared<Dropdown>(Bounds(0, 0, 300, 30), folders)) ); + children.push_back( Layout::Ptr(std::make_shared<Text>(name, Vec2(), White, gui::Font(0.6))) ); + children.push_back( Layout::Ptr(std::make_shared<Dropdown>(Bounds(0, 0, 300, 28), folders)) ); + ((Dropdown*)children.back().get())->textfield()->set_font(Font(0.6)); } else { - children.push_back( Layout::Ptr(std::make_shared<Text>(name, Vec2(), White, gui::Font(0.7, Style::Bold))) ); - children.push_back( Layout::Ptr(std::make_shared<Textfield>(start, Bounds(0, 0, 300, 30)))); + children.push_back( Layout::Ptr(std::make_shared<Text>(name, Vec2(), White, gui::Font(0.6))) ); + children.push_back( Layout::Ptr(std::make_shared<Textfield>(start, Bounds(0, 0, 300, 28)))); + ((Textfield*)children.back().get())->set_font(Font(0.6)); } if(name == "output_prefix") { diff --git a/Application/src/tracker/VideoOpener.h b/Application/src/tracker/VideoOpener.h index a6360d7caabc9b59b779faf1984220336aa5839a..5e86854a6fae95068503d87909b251118bcdedc2 100644 --- a/Application/src/tracker/VideoOpener.h +++ b/Application/src/tracker/VideoOpener.h @@ -83,7 +83,7 @@ public: : _text(std::make_shared<gui::Text>(name)) //_joint(std::make_shared<gui::HorizontalLayout>(std::vector<Layout::Ptr>{_text, _text_field})) { - _text->set_font(Font(0.75, Style::Bold)); + _text->set_font(Font(0.6)); _text->set_color(White); } @@ -114,6 +114,16 @@ public: } void update() override; }; + struct LabeledCheckbox : public LabeledField { + gui::derived_ptr<gui::Checkbox> _checkbox; + sprite::Reference _ref; + LabeledCheckbox(const std::string& name = ""); + void add_to(std::vector<Layout::Ptr>& v) override { + LabeledField::add_to(v); + v.push_back(_checkbox); + } + void update() override; + }; std::map<std::string, std::unique_ptr<LabeledField>> _text_fields; gui::Checkbox *_load_results_checkbox = nullptr; diff --git a/Application/src/tracker/gui/gui.cpp b/Application/src/tracker/gui/gui.cpp index 9f955155d6e3f1754deb9685b9dfa4510c189c7e..8dcbfcfc290f57fcd139adc1a555f7ceaac1ff56 100644 --- a/Application/src/tracker/gui/gui.cpp +++ b/Application/src/tracker/gui/gui.cpp @@ -1220,11 +1220,12 @@ void GUI::reanalyse_from(long_t frame, bool in_thread) { gui->analysis()->set_paused(true).get(); { + Tracker::instance()->wait(); + std::lock_guard<std::recursive_mutex> gguard(gui->gui().lock()); Tracker::LockGuard guard("reanalyse_from"); if(frame <= Tracker::end_frame()) { - Tracker::instance()->wait(); Tracker::instance()->_remove_frames(frame); gui->removed_frames(frame); diff --git a/Application/src/tracker/main.cpp b/Application/src/tracker/main.cpp index f9ca584f81225246e45f528bdc99e58dec39cd27..505e975f764a150b601066754ef545ca836073cc 100644 --- a/Application/src/tracker/main.cpp +++ b/Application/src/tracker/main.cpp @@ -1186,6 +1186,8 @@ int main(int argc, char** argv) Debug("Paused."); } }); + + Debug("Added."); } } }); diff --git a/Application/src/tracker/tracking/Tracker.cpp b/Application/src/tracker/tracking/Tracker.cpp index 0c8c0353f974ac012de4bb708282f879bd12c704..815cbdc338027ed4122329742fcc5778fc2f2fc7 100644 --- a/Application/src/tracker/tracking/Tracker.cpp +++ b/Application/src/tracker/tracking/Tracker.cpp @@ -350,9 +350,10 @@ void Tracker::analysis_state(AnalysisState pause) { if (!callback_registered) { auto variable_changed = [](auto&map, auto&key, auto&value){ if(contains(Settings::names(), key)) { - Tracker::LockGuard guard("changed_settings"); - Settings :: variable_changed(map, key, value); - }}; + Tracker::LockGuard guard("changed_settings"); + Settings :: variable_changed(map, key, value); + } + }; cmn::GlobalSettings::map().register_callback((void*)"Settings", variable_changed); for(auto &n : Settings :: names()) variable_changed(cmn::GlobalSettings::map(), n, cmn::GlobalSettings::get(n).get()); @@ -3458,7 +3459,6 @@ void Tracker::update_iterator_maps(long_t frame, const Tracker::set_of_individua } void Tracker::wait() { - LockGuard guard("Tracker::wait()"); recognition_pool.wait(); }