Browse Source

Improvement of selection and completion dialogs and tooltips. Can now open selection dialogs (Find Symbol (Ctags), Backtrace, Show Variables) without an opened buffer.

merge-requests/365/head
eidheim 9 years ago
parent
commit
cf5a509cbc
  1. 2
      src/CMakeLists.txt
  2. 4
      src/notebook.cc
  3. 102
      src/project.cc
  4. 116
      src/selection_dialog.cc
  5. 27
      src/selection_dialog.h
  6. 25
      src/source.cc
  7. 2
      src/source.h
  8. 45
      src/source_clang.cc
  9. 2
      src/source_clang.h
  10. 25
      src/source_spellcheck.cc
  11. 3
      src/source_spellcheck.h
  12. 70
      src/tooltips.cc
  13. 5
      src/tooltips.h
  14. 119
      src/window.cc
  15. 2
      tests/CMakeLists.txt
  16. 12
      tests/stubs/selection_dialog.cc
  17. 2
      tests/stubs/tooltips.cc

2
src/CMakeLists.txt

@ -12,7 +12,7 @@ set(project_files
juci.cc juci.cc
notebook.cc notebook.cc
project.cc project.cc
selectiondialog.cc selection_dialog.cc
terminal.cc terminal.cc
tooltips.cc tooltips.cc
window.cc window.cc

4
src/notebook.cc

@ -5,6 +5,7 @@
#include <regex> #include <regex>
#include "project.h" #include "project.h"
#include "filesystem.h" #include "filesystem.h"
#include "selection_dialog.h"
#if GTKSOURCEVIEWMM_MAJOR_VERSION > 3 || (GTKSOURCEVIEWMM_MAJOR_VERSION == 3 && GTKSOURCEVIEWMM_MINOR_VERSION >= 18) #if GTKSOURCEVIEWMM_MAJOR_VERSION > 3 || (GTKSOURCEVIEWMM_MAJOR_VERSION == 3 && GTKSOURCEVIEWMM_MINOR_VERSION >= 18)
#include "gtksourceview-3.0/gtksourceview/gtksourcemap.h" #include "gtksourceview-3.0/gtksourceview/gtksourcemap.h"
@ -522,6 +523,9 @@ bool Notebook::close(size_t index) {
delete_cursor_locations(view); delete_cursor_locations(view);
SelectionDialog::get()=nullptr;
CompletionDialog::get()=nullptr;
if(auto clang_view=dynamic_cast<Source::ClangView*>(view)) if(auto clang_view=dynamic_cast<Source::ClangView*>(view))
clang_view->async_delete(); clang_view->async_delete();
else else

102
src/project.cc

@ -6,6 +6,7 @@
#include <fstream> #include <fstream>
#include "menu.h" #include "menu.h"
#include "notebook.h" #include "notebook.h"
#include "selection_dialog.h"
#ifdef JUCI_ENABLE_DEBUG #ifdef JUCI_ENABLE_DEBUG
#include "debug_lldb.h" #include "debug_lldb.h"
#endif #endif
@ -91,10 +92,10 @@ void Project::debug_activate_menu_items() {
menu.actions["debug_step_over"]->set_enabled(!debug_status.empty()); menu.actions["debug_step_over"]->set_enabled(!debug_status.empty());
menu.actions["debug_step_into"]->set_enabled(!debug_status.empty()); menu.actions["debug_step_into"]->set_enabled(!debug_status.empty());
menu.actions["debug_step_out"]->set_enabled(!debug_status.empty()); menu.actions["debug_step_out"]->set_enabled(!debug_status.empty());
menu.actions["debug_backtrace"]->set_enabled(!debug_status.empty() && view); menu.actions["debug_backtrace"]->set_enabled(!debug_status.empty());
menu.actions["debug_show_variables"]->set_enabled(!debug_status.empty() && view); menu.actions["debug_show_variables"]->set_enabled(!debug_status.empty());
menu.actions["debug_run_command"]->set_enabled(!debug_status.empty()); menu.actions["debug_run_command"]->set_enabled(!debug_status.empty());
menu.actions["debug_toggle_breakpoint"]->set_enabled(view && static_cast<bool>(view->toggle_breakpoint)); menu.actions["debug_toggle_breakpoint"]->set_enabled(view && view->toggle_breakpoint);
menu.actions["debug_goto_stop"]->set_enabled(!debug_status.empty()); menu.actions["debug_goto_stop"]->set_enabled(!debug_status.empty());
} }
@ -493,12 +494,16 @@ void Project::Clang::debug_step_out() {
} }
void Project::Clang::debug_backtrace() { void Project::Clang::debug_backtrace() {
auto view=Notebook::get().get_current_view(); if(debugging) {
if(view && debugging) { auto view=Notebook::get().get_current_view();
auto backtrace=Debug::LLDB::get().get_backtrace(); auto backtrace=Debug::LLDB::get().get_backtrace();
auto iter=view->get_iter_for_dialog(); if(view) {
view->selection_dialog=std::make_unique<SelectionDialog>(*view, view->get_buffer()->create_mark(iter), true, true); auto iter=view->get_iter_for_dialog();
SelectionDialog::create(view, view->get_buffer()->create_mark(iter), true, true);
}
else
SelectionDialog::create(true, true);
auto rows=std::make_shared<std::unordered_map<std::string, Debug::LLDB::Frame> >(); auto rows=std::make_shared<std::unordered_map<std::string, Debug::LLDB::Frame> >();
if(backtrace.size()==0) { if(backtrace.size()==0) {
Info::get().print("No backtrace found"); Info::get().print("No backtrace found");
@ -520,14 +525,14 @@ void Project::Clang::debug_backtrace() {
row+=":<b>"+Glib::Markup::escape_text(file_path)+":"+std::to_string(frame.line_nr)+"</b> - "+Glib::Markup::escape_text(frame.function_name); row+=":<b>"+Glib::Markup::escape_text(file_path)+":"+std::to_string(frame.line_nr)+"</b> - "+Glib::Markup::escape_text(frame.function_name);
} }
(*rows)[row]=frame; (*rows)[row]=frame;
view->selection_dialog->add_row(row); SelectionDialog::get()->add_row(row);
if(!cursor_set && frame.file_path==view->file_path) { if(!cursor_set && view && frame.file_path==view->file_path) {
view->selection_dialog->set_cursor_at_last_row(); SelectionDialog::get()->set_cursor_at_last_row();
cursor_set=true; cursor_set=true;
} }
} }
view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { SelectionDialog::get()->on_select=[this, rows](const std::string& selected, bool hide_window) {
auto frame=rows->at(selected); auto frame=rows->at(selected);
if(!frame.file_path.empty()) { if(!frame.file_path.empty()) {
Notebook::get().open(frame.file_path); Notebook::get().open(frame.file_path);
@ -539,18 +544,24 @@ void Project::Clang::debug_backtrace() {
} }
} }
}; };
view->hide_tooltips(); if(view)
view->selection_dialog->show(); view->hide_tooltips();
SelectionDialog::get()->show();
} }
} }
void Project::Clang::debug_show_variables() { void Project::Clang::debug_show_variables() {
auto view=Notebook::get().get_current_view(); if(debugging) {
if(debugging && view) { auto view=Notebook::get().get_current_view();
auto variables=Debug::LLDB::get().get_variables(); auto variables=Debug::LLDB::get().get_variables();
auto iter=view->get_iter_for_dialog(); Gtk::TextIter iter;
view->selection_dialog=std::make_unique<SelectionDialog>(*view, view->get_buffer()->create_mark(iter), true, true); if(view) {
iter=view->get_iter_for_dialog();
SelectionDialog::create(view, view->get_buffer()->create_mark(iter), true, true);
}
else
SelectionDialog::create(true, true);
auto rows=std::make_shared<std::unordered_map<std::string, Debug::LLDB::Variable> >(); auto rows=std::make_shared<std::unordered_map<std::string, Debug::LLDB::Variable> >();
if(variables.size()==0) { if(variables.size()==0) {
Info::get().print("No variables found"); Info::get().print("No variables found");
@ -561,10 +572,10 @@ void Project::Clang::debug_show_variables() {
std::string row="#"+std::to_string(variable.thread_index_id)+":#"+std::to_string(variable.frame_index)+":"+variable.file_path.filename().string()+":"+std::to_string(variable.line_nr)+" - <b>"+Glib::Markup::escape_text(variable.name)+"</b>"; std::string row="#"+std::to_string(variable.thread_index_id)+":#"+std::to_string(variable.frame_index)+":"+variable.file_path.filename().string()+":"+std::to_string(variable.line_nr)+" - <b>"+Glib::Markup::escape_text(variable.name)+"</b>";
(*rows)[row]=variable; (*rows)[row]=variable;
view->selection_dialog->add_row(row); SelectionDialog::get()->add_row(row);
} }
view->selection_dialog->on_select=[this, rows](const std::string& selected, bool hide_window) { SelectionDialog::get()->on_select=[this, rows](const std::string& selected, bool hide_window) {
auto variable=rows->at(selected); auto variable=rows->at(selected);
Debug::LLDB::get().select_frame(variable.frame_index, variable.thread_index_id); Debug::LLDB::get().select_frame(variable.frame_index, variable.thread_index_id);
if(!variable.file_path.empty()) { if(!variable.file_path.empty()) {
@ -578,44 +589,49 @@ void Project::Clang::debug_show_variables() {
Info::get().print("Debugger did not find declaration for the variable: "+variable.name); Info::get().print("Debugger did not find declaration for the variable: "+variable.name);
}; };
view->selection_dialog->on_hide=[this]() { SelectionDialog::get()->on_hide=[this]() {
debug_variable_tooltips.hide(); debug_variable_tooltips.hide();
debug_variable_tooltips.clear(); debug_variable_tooltips.clear();
}; };
view->selection_dialog->on_changed=[this, rows, iter](const std::string &selected) { SelectionDialog::get()->on_changed=[this, rows, view, iter](const std::string &selected) {
if(selected.empty()) { if(selected.empty()) {
debug_variable_tooltips.hide(); debug_variable_tooltips.hide();
return; return;
} }
if(auto view=Notebook::get().get_current_view()) { debug_variable_tooltips.clear();
debug_variable_tooltips.clear(); auto create_tooltip_buffer=[this, rows, view, selected]() {
auto create_tooltip_buffer=[this, rows, view, selected]() { auto variable=rows->at(selected);
auto variable=rows->at(selected); auto tooltip_buffer=view?Gtk::TextBuffer::create(view->get_buffer()->get_tag_table()):Gtk::TextBuffer::create();
auto tooltip_buffer=Gtk::TextBuffer::create(view->get_buffer()->get_tag_table());
Glib::ustring value=variable.value;
Glib::ustring value=variable.value; if(!value.empty()) {
if(!value.empty()) { Glib::ustring::iterator iter;
Glib::ustring::iterator iter; while(!value.validate(iter)) {
while(!value.validate(iter)) { auto next_char_iter=iter;
auto next_char_iter=iter; next_char_iter++;
next_char_iter++; value.replace(iter, next_char_iter, "?");
value.replace(iter, next_char_iter, "?");
}
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), value.substr(0, value.size()-1), "def:note");
} }
if(view)
tooltip_buffer->insert_with_tag(tooltip_buffer->get_insert()->get_iter(), value.substr(0, value.size()-1), "def:note");
else
tooltip_buffer->insert(tooltip_buffer->get_insert()->get_iter(), value.substr(0, value.size()-1));
}
return tooltip_buffer; return tooltip_buffer;
}; };
debug_variable_tooltips.emplace_back(create_tooltip_buffer, *view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter)); if(view)
debug_variable_tooltips.emplace_back(create_tooltip_buffer, view, view->get_buffer()->create_mark(iter), view->get_buffer()->create_mark(iter));
else
debug_variable_tooltips.emplace_back(create_tooltip_buffer);
debug_variable_tooltips.show(true); debug_variable_tooltips.show(true);
}
}; };
view->hide_tooltips(); if(view)
view->selection_dialog->show(); view->hide_tooltips();
SelectionDialog::get()->show();
} }
} }

116
src/selectiondialog.cc → src/selection_dialog.cc

@ -1,4 +1,4 @@
#include "selectiondialog.h" #include "selection_dialog.h"
#include <algorithm> #include <algorithm>
namespace sigc { namespace sigc {
@ -43,7 +43,7 @@ void SelectionDialogBase::ListViewText::clear() {
list_store.reset(); list_store.reset();
} }
SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup): SelectionDialogBase::SelectionDialogBase(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup):
text_view(text_view), window(Gtk::WindowType::WINDOW_POPUP), vbox(Gtk::Orientation::ORIENTATION_VERTICAL), list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_search_entry) { text_view(text_view), window(Gtk::WindowType::WINDOW_POPUP), vbox(Gtk::Orientation::ORIENTATION_VERTICAL), list_view_text(use_markup), start_mark(start_mark), show_search_entry(show_search_entry) {
auto g_application=g_application_get_default(); auto g_application=g_application_get_default();
auto gio_application=Glib::wrap(g_application, true); auto gio_application=Glib::wrap(g_application, true);
@ -67,26 +67,63 @@ SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<
window.add(vbox); window.add(vbox);
list_view_text.signal_realize().connect([this](){ list_view_text.signal_realize().connect([this](){
resize(); auto g_application=g_application_get_default();
auto gio_application=Glib::wrap(g_application, true);
auto application=Glib::RefPtr<Gtk::Application>::cast_static(gio_application);
auto application_window=application->get_active_window();
int row_width=0, row_height;
Gdk::Rectangle rect;
list_view_text.get_cell_area(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin()), *(list_view_text.get_column(0)), rect);
row_width=rect.get_width();
row_height=rect.get_height();
row_width+=rect.get_x()*2; //TODO: Add correct margin x and y
row_height+=rect.get_y()*2;
if(this->text_view && row_width>this->text_view->get_width()*2/3)
row_width=this->text_view->get_width()*2/3;
else if(row_width>application_window->get_width()/2)
row_width=application_window->get_width()/2;
else
scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC);
int window_height=std::min(row_height*static_cast<int>(list_view_text.get_model()->children().size()), row_height*10);
if(this->show_search_entry)
window_height+=search_entry.get_height();
int window_width=row_width+1;
window.resize(window_width, window_height);
if(this->text_view) {
Gdk::Rectangle iter_rect;
this->text_view->get_iter_location(this->start_mark->get_iter(), iter_rect);
Gdk::Rectangle visible_rect;
this->text_view->get_visible_rect(visible_rect);
int buffer_x=std::max(iter_rect.get_x(), visible_rect.get_x());
int buffer_y=iter_rect.get_y()+iter_rect.get_height();
int window_x, window_y;
this->text_view->buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, buffer_x, buffer_y, window_x, window_y);
int root_x, root_y;
this->text_view->get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(window_x, window_y, root_x, root_y);
window.move(root_x, root_y+1); //TODO: replace 1 with some margin
}
else {
int root_x, root_y;
application_window->get_position(root_x, root_y);
root_x+=application_window->get_width()/2-window_width/2;
root_y+=application_window->get_height()/2-window_height/2;
window.move(root_x, root_y);
}
}); });
list_view_text.signal_cursor_changed().connect([this] { list_view_text.signal_cursor_changed().connect([this] {
cursor_changed(); cursor_changed();
}); });
}
window.signal_realize().connect([this] { SelectionDialogBase::~SelectionDialogBase() {
Gdk::Rectangle iter_rect; if(text_view)
this->text_view.get_iter_location(this->start_mark->get_iter(), iter_rect); text_view->get_buffer()->delete_mark(start_mark);
Gdk::Rectangle visible_rect;
this->text_view.get_visible_rect(visible_rect);
int buffer_x=std::max(iter_rect.get_x(), visible_rect.get_x());
int buffer_y=iter_rect.get_y()+iter_rect.get_height();
int window_x, window_y;
this->text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, buffer_x, buffer_y, window_x, window_y);
int root_x, root_y;
this->text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(window_x, window_y, root_x, root_y);
window.move(root_x, root_y+1); //TODO: replace 1 with some margin
});
} }
void SelectionDialogBase::cursor_changed() { void SelectionDialogBase::cursor_changed() {
@ -102,18 +139,14 @@ void SelectionDialogBase::cursor_changed() {
on_changed(row); on_changed(row);
last_row=row; last_row=row;
} }
SelectionDialogBase::~SelectionDialogBase() {
text_view.get_buffer()->delete_mark(start_mark);
}
void SelectionDialogBase::add_row(const std::string& row) { void SelectionDialogBase::add_row(const std::string& row) {
list_view_text.append(row); list_view_text.append(row);
} }
void SelectionDialogBase::show() { void SelectionDialogBase::show() {
window.show_all(); window.show_all();
text_view.grab_focus(); if(text_view)
text_view->grab_focus();
if(list_view_text.get_model()->children().size()>0) { if(list_view_text.get_model()->children().size()>0) {
if(!list_view_text.get_selection()->get_selected()) { if(!list_view_text.get_selection()->get_selected()) {
@ -146,30 +179,9 @@ void SelectionDialogBase::hide() {
list_view_text.clear(); list_view_text.clear();
} }
void SelectionDialogBase::resize() { std::unique_ptr<SelectionDialog> SelectionDialog::instance;
if(list_view_text.get_realized()) {
int row_width=0, row_height;
Gdk::Rectangle rect;
list_view_text.get_cell_area(list_view_text.get_model()->get_path(list_view_text.get_model()->children().begin()), *(list_view_text.get_column(0)), rect);
row_width=rect.get_width();
row_height=rect.get_height();
row_width+=rect.get_x()*2; //TODO: Add correct margin x and y SelectionDialog::SelectionDialog(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {
row_height+=rect.get_y()*2;
if(row_width>text_view.get_width()/2)
row_width=text_view.get_width()/2;
else
scrolled_window.set_policy(Gtk::PolicyType::POLICY_NEVER, Gtk::PolicyType::POLICY_AUTOMATIC);
int window_height=std::min(row_height*static_cast<int>(list_view_text.get_model()->children().size()), row_height*10);
if(show_search_entry)
window_height+=search_entry.get_height();
window.resize(row_width+1, window_height);
}
}
SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup) : SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {
std::shared_ptr<std::string> search_key(new std::string()); std::shared_ptr<std::string> search_key(new std::string());
auto filter_model=Gtk::TreeModelFilter::create(list_view_text.get_model()); auto filter_model=Gtk::TreeModelFilter::create(list_view_text.get_model());
@ -288,8 +300,10 @@ bool SelectionDialog::on_key_press(GdkEventKey* key) {
return false; return false;
} }
CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark) : SelectionDialogBase(text_view, start_mark, false, false) { std::unique_ptr<CompletionDialog> CompletionDialog::instance;
show_offset=text_view.get_buffer()->get_insert()->get_iter().get_offset();
CompletionDialog::CompletionDialog(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark) : SelectionDialogBase(text_view, start_mark, false, false) {
show_offset=text_view->get_buffer()->get_insert()->get_iter().get_offset();
std::shared_ptr<std::string> search_key(new std::string()); std::shared_ptr<std::string> search_key(new std::string());
auto filter_model=Gtk::TreeModelFilter::create(list_view_text.get_model()); auto filter_model=Gtk::TreeModelFilter::create(list_view_text.get_model());
@ -325,7 +339,7 @@ CompletionDialog::CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::T
select(); select();
}); });
auto text=text_view.get_buffer()->get_text(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); auto text=text_view->get_buffer()->get_text(start_mark->get_iter(), text_view->get_buffer()->get_insert()->get_iter());
if(text.size()>0) { if(text.size()>0) {
search_entry.set_text(text); search_entry.set_text(text);
list_view_text.set_search_entry(search_entry); list_view_text.set_search_entry(search_entry);
@ -349,11 +363,11 @@ bool CompletionDialog::on_key_release(GdkEventKey* key) {
if(key->keyval==GDK_KEY_Down || key->keyval==GDK_KEY_KP_Down || key->keyval==GDK_KEY_Up || key->keyval==GDK_KEY_KP_Up) if(key->keyval==GDK_KEY_Down || key->keyval==GDK_KEY_KP_Down || key->keyval==GDK_KEY_Up || key->keyval==GDK_KEY_KP_Up)
return false; return false;
if(show_offset>text_view.get_buffer()->get_insert()->get_iter().get_offset()) { if(show_offset>text_view->get_buffer()->get_insert()->get_iter().get_offset()) {
hide(); hide();
} }
else { else {
auto text=text_view.get_buffer()->get_text(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); auto text=text_view->get_buffer()->get_text(start_mark->get_iter(), text_view->get_buffer()->get_insert()->get_iter());
search_entry.set_text(text); search_entry.set_text(text);
list_view_text.set_search_entry(search_entry); list_view_text.set_search_entry(search_entry);
if(text=="") { if(text=="") {
@ -371,7 +385,7 @@ bool CompletionDialog::on_key_press(GdkEventKey* key) {
(key->keyval>=GDK_KEY_a && key->keyval<=GDK_KEY_z) || (key->keyval>=GDK_KEY_a && key->keyval<=GDK_KEY_z) ||
key->keyval==GDK_KEY_underscore || key->keyval==GDK_KEY_BackSpace) { key->keyval==GDK_KEY_underscore || key->keyval==GDK_KEY_BackSpace) {
if(row_in_entry) { if(row_in_entry) {
text_view.get_buffer()->erase(start_mark->get_iter(), text_view.get_buffer()->get_insert()->get_iter()); text_view->get_buffer()->erase(start_mark->get_iter(), text_view->get_buffer()->get_insert()->get_iter());
row_in_entry=false; row_in_entry=false;
if(key->keyval==GDK_KEY_BackSpace) if(key->keyval==GDK_KEY_BackSpace)
return true; return true;

27
src/selectiondialog.h → src/selection_dialog.h

@ -31,13 +31,15 @@ class SelectionDialogBase {
}; };
public: public:
SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup); SelectionDialogBase(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup);
~SelectionDialogBase(); virtual ~SelectionDialogBase();
void add_row(const std::string& row); void add_row(const std::string& row);
void set_cursor_at_last_row(); void set_cursor_at_last_row();
void show(); void show();
void hide(); void hide();
bool is_visible() {return window.is_visible();} bool is_visible() {return window.is_visible();}
void get_position(int &root_x, int &root_y) {window.get_position(root_x, root_y);}
std::function<void()> on_hide; std::function<void()> on_hide;
std::function<void(const std::string& selected, bool hide_window)> on_select; std::function<void(const std::string& selected, bool hide_window)> on_select;
@ -47,8 +49,7 @@ public:
protected: protected:
void cursor_changed(); void cursor_changed();
void resize(); Gtk::TextView *text_view;
Gtk::TextView& text_view;
Gtk::Window window; Gtk::Window window;
Gtk::Box vbox; Gtk::Box vbox;
Gtk::ScrolledWindow scrolled_window; Gtk::ScrolledWindow scrolled_window;
@ -60,17 +61,31 @@ protected:
}; };
class SelectionDialog : public SelectionDialogBase { class SelectionDialog : public SelectionDialogBase {
SelectionDialog(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup);
static std::unique_ptr<SelectionDialog> instance;
public: public:
SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry=true, bool use_markup=false);
bool on_key_press(GdkEventKey* key); bool on_key_press(GdkEventKey* key);
static void create(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry=true, bool use_markup=false) {
instance=std::unique_ptr<SelectionDialog>(new SelectionDialog(text_view, start_mark, show_search_entry, use_markup));
}
static void create(bool show_search_entry=true, bool use_markup=false) {
instance=std::unique_ptr<SelectionDialog>(new SelectionDialog(nullptr, Glib::RefPtr<Gtk::TextBuffer::Mark>(), show_search_entry, use_markup));
}
static std::unique_ptr<SelectionDialog> &get() {return instance;}
}; };
class CompletionDialog : public SelectionDialogBase { class CompletionDialog : public SelectionDialogBase {
CompletionDialog(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark);
static std::unique_ptr<CompletionDialog> instance;
public: public:
CompletionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark);
bool on_key_release(GdkEventKey* key); bool on_key_release(GdkEventKey* key);
bool on_key_press(GdkEventKey* key); bool on_key_press(GdkEventKey* key);
static void create(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark) {
instance=std::unique_ptr<CompletionDialog>(new CompletionDialog(text_view, start_mark));
}
static std::unique_ptr<CompletionDialog> &get() {return instance;}
private: private:
void select(bool hide_window=true); void select(bool hide_window=true);

25
src/source.cc

@ -5,6 +5,7 @@
#include "info.h" #include "info.h"
#include "directories.h" #include "directories.h"
#include "menu.h" #include "menu.h"
#include "selection_dialog.h"
#include <gtksourceview/gtksource.h> #include <gtksourceview/gtksource.h>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/spirit/home/qi/char.hpp> #include <boost/spirit/home/qi/char.hpp>
@ -647,10 +648,10 @@ void Source::View::set_tooltip_and_dialog_events() {
return false; return false;
}, 500); }, 500);
if(autocomplete_dialog) if(SelectionDialog::get())
autocomplete_dialog->hide(); SelectionDialog::get()->hide();
if(selection_dialog) if(CompletionDialog::get())
selection_dialog->hide(); CompletionDialog::get()->hide();
if(update_status_location) if(update_status_location)
update_status_location(this); update_status_location(this);
@ -947,10 +948,10 @@ void Source::View::hide_tooltips() {
void Source::View::hide_dialogs() { void Source::View::hide_dialogs() {
SpellCheckView::hide_dialogs(); SpellCheckView::hide_dialogs();
if(selection_dialog) if(SelectionDialog::get())
selection_dialog->hide(); SelectionDialog::get()->hide();
if(autocomplete_dialog) if(CompletionDialog::get())
autocomplete_dialog->hide(); CompletionDialog::get()->hide();
} }
std::string Source::View::get_line(const Gtk::TextIter &iter) { std::string Source::View::get_line(const Gtk::TextIter &iter) {
@ -1244,12 +1245,12 @@ std::string Source::View::get_token(Gtk::TextIter iter) {
} }
bool Source::View::on_key_press_event(GdkEventKey* key) { bool Source::View::on_key_press_event(GdkEventKey* key) {
if(selection_dialog && selection_dialog->is_visible()) { if(SelectionDialog::get() && SelectionDialog::get()->is_visible()) {
if(selection_dialog->on_key_press(key)) if(SelectionDialog::get()->on_key_press(key))
return true; return true;
} }
if(autocomplete_dialog && autocomplete_dialog->is_visible()) { if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) {
if(autocomplete_dialog->on_key_press(key)) if(CompletionDialog::get()->on_key_press(key))
return true; return true;
} }

2
src/source.h

@ -80,8 +80,6 @@ namespace Source {
std::function<void()> add_documentation; std::function<void()> add_documentation;
std::function<void(int)> toggle_breakpoint; std::function<void(int)> toggle_breakpoint;
std::unique_ptr<CompletionDialog> autocomplete_dialog;
std::unique_ptr<SelectionDialog> selection_dialog;
Gtk::TextIter get_iter_for_dialog(); Gtk::TextIter get_iter_for_dialog();
std::function<void(View* view, bool center, bool show_tooltips)> scroll_to_cursor_delayed=[](View* view, bool center, bool show_tooltips) {}; std::function<void(View* view, bool center, bool show_tooltips)> scroll_to_cursor_delayed=[](View* view, bool center, bool show_tooltips) {};

45
src/source_clang.cc

@ -8,6 +8,7 @@
#include "info.h" #include "info.h"
#include "dialogs.h" #include "dialogs.h"
#include "ctags.h" #include "ctags.h"
#include "selection_dialog.h"
namespace sigc { namespace sigc {
#ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
@ -455,7 +456,7 @@ void Source::ClangViewParse::update_diagnostics() {
} }
return tooltip_buffer; return tooltip_buffer;
}; };
diagnostic_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); diagnostic_tooltips.emplace_back(create_tooltip_buffer, this, get_buffer()->create_mark(start), get_buffer()->create_mark(end));
get_buffer()->apply_tag_by_name(diagnostic_tag_name+"_underline", start, end); get_buffer()->apply_tag_by_name(diagnostic_tag_name+"_underline", start, end);
auto iter=get_buffer()->get_insert()->get_iter(); auto iter=get_buffer()->get_insert()->get_iter();
@ -554,7 +555,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle)
return tooltip_buffer; return tooltip_buffer;
}; };
type_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(start), get_buffer()->create_mark(end)); type_tooltips.emplace_back(create_tooltip_buffer, this, get_buffer()->create_mark(start), get_buffer()->create_mark(end));
type_tooltips.show(); type_tooltips.show();
return; return;
} }
@ -568,7 +569,7 @@ void Source::ClangViewParse::show_type_tooltips(const Gdk::Rectangle &rectangle)
Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language): Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::path &file_path, Glib::RefPtr<Gsv::Language> language):
Source::ClangViewParse(file_path, language), autocomplete_state(AutocompleteState::IDLE) { Source::ClangViewParse(file_path, language), autocomplete_state(AutocompleteState::IDLE) {
get_buffer()->signal_changed().connect([this](){ get_buffer()->signal_changed().connect([this](){
if(autocomplete_dialog && autocomplete_dialog->is_visible()) if(CompletionDialog::get() && CompletionDialog::get()->is_visible())
delayed_reparse_connection.disconnect(); delayed_reparse_connection.disconnect();
else { else {
if(!has_focus()) if(!has_focus())
@ -596,8 +597,8 @@ Source::ClangViewAutocomplete::ClangViewAutocomplete(const boost::filesystem::pa
}); });
signal_key_release_event().connect([this](GdkEventKey* key){ signal_key_release_event().connect([this](GdkEventKey* key){
if(autocomplete_dialog && autocomplete_dialog->is_visible()) { if(CompletionDialog::get() && CompletionDialog::get()->is_visible()) {
if(autocomplete_dialog->on_key_release(key)) if(CompletionDialog::get()->on_key_release(key))
return true; return true;
} }
return false; return false;
@ -614,19 +615,19 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() {
auto start_iter=get_buffer()->get_insert()->get_iter(); auto start_iter=get_buffer()->get_insert()->get_iter();
if(prefix.size()>0 && !start_iter.backward_chars(prefix.size())) if(prefix.size()>0 && !start_iter.backward_chars(prefix.size()))
return; return;
autocomplete_dialog=std::make_unique<CompletionDialog>(*this, get_buffer()->create_mark(start_iter)); CompletionDialog::create(this, get_buffer()->create_mark(start_iter));
autocomplete_dialog_rows.clear(); completion_dialog_rows.clear();
autocomplete_dialog->on_hide=[this](){ CompletionDialog::get()->on_hide=[this](){
get_buffer()->end_user_action(); get_buffer()->end_user_action();
autocomplete_tooltips.hide(); autocomplete_tooltips.hide();
autocomplete_tooltips.clear(); autocomplete_tooltips.clear();
parsed=false; parsed=false;
soft_reparse(); soft_reparse();
}; };
autocomplete_dialog->on_select=[this](const std::string& selected, bool hide_window) { CompletionDialog::get()->on_select=[this](const std::string& selected, bool hide_window) {
auto row = autocomplete_dialog_rows.at(selected).first; auto row = completion_dialog_rows.at(selected).first;
//erase existing variable or function before insert iter //erase existing variable or function before insert iter
get_buffer()->erase(autocomplete_dialog->start_mark->get_iter(), get_buffer()->get_insert()->get_iter()); get_buffer()->erase(CompletionDialog::get()->start_mark->get_iter(), get_buffer()->get_insert()->get_iter());
//do not insert template argument or function parameters if they already exist //do not insert template argument or function parameters if they already exist
auto iter=get_buffer()->get_insert()->get_iter(); auto iter=get_buffer()->get_insert()->get_iter();
if(*iter=='<' || *iter=='(') { if(*iter=='<' || *iter=='(') {
@ -640,7 +641,7 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() {
auto it=manipulators_map.find(row); auto it=manipulators_map.find(row);
if(it!=manipulators_map.end()) if(it!=manipulators_map.end())
row=it->second; row=it->second;
get_buffer()->insert(autocomplete_dialog->start_mark->get_iter(), row); get_buffer()->insert(CompletionDialog::get()->start_mark->get_iter(), row);
//if selection is finalized, select text inside template arguments or function parameters //if selection is finalized, select text inside template arguments or function parameters
if(hide_window) { if(hide_window) {
auto para_pos=row.find('('); auto para_pos=row.find('(');
@ -668,8 +669,8 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() {
} }
} }
if(start_pos!=std::string::npos && end_pos!=std::string::npos) { if(start_pos!=std::string::npos && end_pos!=std::string::npos) {
auto start_offset=autocomplete_dialog->start_mark->get_iter().get_offset()+start_pos+1; auto start_offset=CompletionDialog::get()->start_mark->get_iter().get_offset()+start_pos+1;
auto end_offset=autocomplete_dialog->start_mark->get_iter().get_offset()+end_pos; auto end_offset=CompletionDialog::get()->start_mark->get_iter().get_offset()+end_pos;
if(start_offset!=end_offset) if(start_offset!=end_offset)
get_buffer()->select_range(get_buffer()->get_iter_at_offset(start_offset), get_buffer()->get_iter_at_offset(end_offset)); get_buffer()->select_range(get_buffer()->get_iter_at_offset(start_offset), get_buffer()->get_iter_at_offset(end_offset));
} }
@ -682,12 +683,12 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() {
} }
}; };
autocomplete_dialog->on_changed=[this](const std::string &selected) { CompletionDialog::get()->on_changed=[this](const std::string &selected) {
if(selected.empty()) { if(selected.empty()) {
autocomplete_tooltips.hide(); autocomplete_tooltips.hide();
return; return;
} }
auto tooltip=std::make_shared<std::string>(autocomplete_dialog_rows.at(selected).second); auto tooltip=std::make_shared<std::string>(completion_dialog_rows.at(selected).second);
if(tooltip->empty()) { if(tooltip->empty()) {
autocomplete_tooltips.hide(); autocomplete_tooltips.hide();
} }
@ -701,8 +702,8 @@ void Source::ClangViewAutocomplete::autocomplete_dialog_setup() {
return tooltip_buffer; return tooltip_buffer;
}; };
auto iter=autocomplete_dialog->start_mark->get_iter(); auto iter=CompletionDialog::get()->start_mark->get_iter();
autocomplete_tooltips.emplace_back(create_tooltip_buffer, *this, get_buffer()->create_mark(iter), get_buffer()->create_mark(iter)); autocomplete_tooltips.emplace_back(create_tooltip_buffer, this, get_buffer()->create_mark(iter), get_buffer()->create_mark(iter));
autocomplete_tooltips.show(true); autocomplete_tooltips.show(true);
} }
@ -808,8 +809,8 @@ void Source::ClangViewAutocomplete::autocomplete() {
auto row_insert_on_selection=row; auto row_insert_on_selection=row;
if(!return_value.empty()) if(!return_value.empty())
row+=" --> " + return_value; row+=" --> " + return_value;
autocomplete_dialog_rows[row] = std::pair<std::string, std::string>(std::move(row_insert_on_selection), std::move(data.brief_comments)); completion_dialog_rows[row] = std::pair<std::string, std::string>(std::move(row_insert_on_selection), std::move(data.brief_comments));
autocomplete_dialog->add_row(row); CompletionDialog::get()->add_row(row);
} }
} }
autocomplete_data->clear(); autocomplete_data->clear();
@ -817,10 +818,10 @@ void Source::ClangViewAutocomplete::autocomplete() {
if(update_status_state) if(update_status_state)
update_status_state(this); update_status_state(this);
autocomplete_state=AutocompleteState::IDLE; autocomplete_state=AutocompleteState::IDLE;
if (!autocomplete_dialog_rows.empty()) { if (!completion_dialog_rows.empty()) {
get_buffer()->begin_user_action(); get_buffer()->begin_user_action();
hide_tooltips(); hide_tooltips();
autocomplete_dialog->show(); CompletionDialog::get()->show();
} }
else else
soft_reparse(); soft_reparse();

2
src/source_clang.h

@ -77,7 +77,7 @@ namespace Source {
void autocomplete_dialog_setup(); void autocomplete_dialog_setup();
void autocomplete_check(); void autocomplete_check();
void autocomplete(); void autocomplete();
std::unordered_map<std::string, std::pair<std::string, std::string> > autocomplete_dialog_rows; std::unordered_map<std::string, std::pair<std::string, std::string> > completion_dialog_rows;
std::vector<AutoCompleteData> autocomplete_get_suggestions(const std::string &buffer, int line_number, int column); std::vector<AutoCompleteData> autocomplete_get_suggestions(const std::string &buffer, int line_number, int column);
Tooltips autocomplete_tooltips; Tooltips autocomplete_tooltips;
std::string prefix; std::string prefix;

25
src/source_spellcheck.cc

@ -1,6 +1,7 @@
#include "source_spellcheck.h" #include "source_spellcheck.h"
#include "config.h" #include "config.h"
#include "info.h" #include "info.h"
#include "selection_dialog.h"
#include <iostream> #include <iostream>
namespace sigc { namespace sigc {
@ -27,8 +28,8 @@ Source::SpellCheckView::SpellCheckView() : Gsv::View() {
spellcheck_error_tag->property_underline()=Pango::Underline::UNDERLINE_ERROR; spellcheck_error_tag->property_underline()=Pango::Underline::UNDERLINE_ERROR;
signal_key_press_event().connect([this](GdkEventKey *event) { signal_key_press_event().connect([this](GdkEventKey *event) {
if(spellcheck_suggestions_dialog && spellcheck_suggestions_dialog->is_visible()) { if(SelectionDialog::get() && SelectionDialog::get()->is_visible()) {
if(spellcheck_suggestions_dialog->on_key_press(event)) if(SelectionDialog::get()->on_key_press(event))
return true; return true;
} }
@ -150,26 +151,26 @@ Source::SpellCheckView::SpellCheckView() : Gsv::View() {
return; return;
if(mark->get_name()=="insert") { if(mark->get_name()=="insert") {
if(spellcheck_suggestions_dialog) if(SelectionDialog::get())
spellcheck_suggestions_dialog->hide(); SelectionDialog::get()->hide();
delayed_spellcheck_suggestions_connection.disconnect(); delayed_spellcheck_suggestions_connection.disconnect();
delayed_spellcheck_suggestions_connection=Glib::signal_timeout().connect([this]() { delayed_spellcheck_suggestions_connection=Glib::signal_timeout().connect([this]() {
if(get_buffer()->get_insert()->get_iter().has_tag(spellcheck_error_tag)) { if(get_buffer()->get_insert()->get_iter().has_tag(spellcheck_error_tag)) {
spellcheck_suggestions_dialog=std::make_unique<SelectionDialog>(*this, get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()), false); SelectionDialog::create(this, get_buffer()->create_mark(get_buffer()->get_insert()->get_iter()), false);
auto word=get_word(get_buffer()->get_insert()->get_iter()); auto word=get_word(get_buffer()->get_insert()->get_iter());
auto suggestions=get_spellcheck_suggestions(word.first, word.second); auto suggestions=get_spellcheck_suggestions(word.first, word.second);
if(suggestions.size()==0) if(suggestions.size()==0)
return false; return false;
for(auto &suggestion: suggestions) for(auto &suggestion: suggestions)
spellcheck_suggestions_dialog->add_row(suggestion); SelectionDialog::get()->add_row(suggestion);
spellcheck_suggestions_dialog->on_select=[this, word](const std::string& selected, bool hide_window) { SelectionDialog::get()->on_select=[this, word](const std::string& selected, bool hide_window) {
get_buffer()->begin_user_action(); get_buffer()->begin_user_action();
get_buffer()->erase(word.first, word.second); get_buffer()->erase(word.first, word.second);
get_buffer()->insert(get_buffer()->get_insert()->get_iter(), selected); get_buffer()->insert(get_buffer()->get_insert()->get_iter(), selected);
get_buffer()->end_user_action(); get_buffer()->end_user_action();
}; };
hide_tooltips(); hide_tooltips();
spellcheck_suggestions_dialog->show(); SelectionDialog::get()->show();
} }
return false; return false;
}, 500); }, 500);
@ -178,8 +179,8 @@ Source::SpellCheckView::SpellCheckView() : Gsv::View() {
get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr<Gtk::TextBuffer::Mark>& mark) { get_buffer()->signal_mark_set().connect([this](const Gtk::TextBuffer::iterator& iterator, const Glib::RefPtr<Gtk::TextBuffer::Mark>& mark) {
if(mark->get_name()=="insert") { if(mark->get_name()=="insert") {
if(spellcheck_suggestions_dialog) if(SelectionDialog::get())
spellcheck_suggestions_dialog->hide(); SelectionDialog::get()->hide();
} }
}); });
@ -240,8 +241,8 @@ void Source::SpellCheckView::configure() {
void Source::SpellCheckView::hide_dialogs() { void Source::SpellCheckView::hide_dialogs() {
delayed_spellcheck_suggestions_connection.disconnect(); delayed_spellcheck_suggestions_connection.disconnect();
if(spellcheck_suggestions_dialog) if(SelectionDialog::get())
spellcheck_suggestions_dialog->hide(); SelectionDialog::get()->hide();
} }
void Source::SpellCheckView::spellcheck(const Gtk::TextIter& start, const Gtk::TextIter& end) { void Source::SpellCheckView::spellcheck(const Gtk::TextIter& start, const Gtk::TextIter& end) {

3
src/source_spellcheck.h

@ -2,7 +2,6 @@
#define JUCI_SOURCE_SPELLCHECK_H_ #define JUCI_SOURCE_SPELLCHECK_H_
#include <gtksourceviewmm.h> #include <gtksourceviewmm.h>
#include <aspell.h> #include <aspell.h>
#include "selectiondialog.h"
namespace Source { namespace Source {
class SpellCheckView : virtual public Gsv::View { class SpellCheckView : virtual public Gsv::View {
@ -24,8 +23,6 @@ namespace Source {
bool spellcheck_all=false; bool spellcheck_all=false;
guint last_keyval=0; guint last_keyval=0;
private: private:
std::unique_ptr<SelectionDialog> spellcheck_suggestions_dialog;
Glib::RefPtr<Gtk::TextTag> spellcheck_error_tag; Glib::RefPtr<Gtk::TextTag> spellcheck_error_tag;
Glib::RefPtr<Gtk::TextTag> comment_tag; Glib::RefPtr<Gtk::TextTag> comment_tag;

70
src/tooltips.cc

@ -1,4 +1,5 @@
#include "tooltips.h" #include "tooltips.h"
#include "selection_dialog.h"
namespace sigc { namespace sigc {
#ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
@ -16,31 +17,35 @@ namespace sigc {
Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle();
Tooltip::Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Gtk::TextView& text_view, Tooltip::Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Gtk::TextView *text_view,
Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark): Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark):
create_tooltip_buffer(create_tooltip_buffer), text_view(text_view), create_tooltip_buffer(create_tooltip_buffer), text_view(text_view),
start_mark(start_mark), end_mark(end_mark) {} start_mark(start_mark), end_mark(end_mark) {}
Tooltip::~Tooltip() { Tooltip::~Tooltip() {
text_view.get_buffer()->delete_mark(start_mark); if(text_view) {
text_view.get_buffer()->delete_mark(end_mark); text_view->get_buffer()->delete_mark(start_mark);
text_view->get_buffer()->delete_mark(end_mark);
}
} }
void Tooltip::update() { void Tooltip::update() {
auto iter=start_mark->get_iter(); if(text_view) {
auto end_iter=end_mark->get_iter(); auto iter=start_mark->get_iter();
text_view.get_iter_location(iter, activation_rectangle); auto end_iter=end_mark->get_iter();
if(iter.get_offset()<end_iter.get_offset()) { text_view->get_iter_location(iter, activation_rectangle);
while(iter.forward_char() && iter!=end_iter) { if(iter.get_offset()<end_iter.get_offset()) {
Gdk::Rectangle rectangle; while(iter.forward_char() && iter!=end_iter) {
text_view.get_iter_location(iter, rectangle); Gdk::Rectangle rectangle;
activation_rectangle.join(rectangle); text_view->get_iter_location(iter, rectangle);
activation_rectangle.join(rectangle);
}
} }
int location_window_x, location_window_y;
text_view->buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, activation_rectangle.get_x(), activation_rectangle.get_y(), location_window_x, location_window_y);
activation_rectangle.set_x(location_window_x);
activation_rectangle.set_y(location_window_y);
} }
int location_window_x, location_window_y;
text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, activation_rectangle.get_x(), activation_rectangle.get_y(), location_window_x, location_window_y);
activation_rectangle.set_x(location_window_x);
activation_rectangle.set_y(location_window_y);
} }
void Tooltip::show(bool disregard_drawn) { void Tooltip::show(bool disregard_drawn) {
@ -64,8 +69,10 @@ void Tooltip::show(bool disregard_drawn) {
tooltip_widget=std::make_unique<Gtk::TextView>(create_tooltip_buffer()); tooltip_widget=std::make_unique<Gtk::TextView>(create_tooltip_buffer());
wrap_lines(tooltip_widget->get_buffer()); wrap_lines(tooltip_widget->get_buffer());
tooltip_widget->set_editable(false); tooltip_widget->set_editable(false);
auto tag=text_view.get_buffer()->get_tag_table()->lookup("def:note_background"); if(text_view) {
tooltip_widget->override_background_color(tag->property_background_rgba()); auto tag=text_view->get_buffer()->get_tag_table()->lookup("def:note_background");
tooltip_widget->override_background_color(tag->property_background_rgba());
}
window->add(*tooltip_widget); window->add(*tooltip_widget);
auto layout=Pango::Layout::create(tooltip_widget->get_pango_context()); auto layout=Pango::Layout::create(tooltip_widget->get_pango_context());
@ -74,19 +81,32 @@ void Tooltip::show(bool disregard_drawn) {
size.second+=2; size.second+=2;
window->signal_realize().connect([this] { window->signal_realize().connect([this] {
if(!text_view) {
auto &dialog=SelectionDialog::get();
if(dialog && dialog->is_visible()) {
int root_x, root_y;
dialog->get_position(root_x, root_y);
position.first=root_x;
position.second=root_y-size.second;
if(position.second<0)
position.second=0;
}
}
window->move(position.first, position.second); window->move(position.first, position.second);
}); });
} }
//Adjust if tooltip is left of text_view int root_x=0, root_y=0;
Gdk::Rectangle visible_rect; if(text_view) {
text_view.get_visible_rect(visible_rect); //Adjust if tooltip is left of text_view
int visible_x, visible_y; Gdk::Rectangle visible_rect;
text_view.buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, visible_rect.get_x(), visible_rect.get_y(), visible_x, visible_y); text_view->get_visible_rect(visible_rect);
auto activation_rectangle_x=std::max(activation_rectangle.get_x(), visible_x); int visible_x, visible_y;
text_view->buffer_to_window_coords(Gtk::TextWindowType::TEXT_WINDOW_TEXT, visible_rect.get_x(), visible_rect.get_y(), visible_x, visible_y);
auto activation_rectangle_x=std::max(activation_rectangle.get_x(), visible_x);
int root_x, root_y; text_view->get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(activation_rectangle_x, activation_rectangle.get_y(), root_x, root_y);
text_view.get_window(Gtk::TextWindowType::TEXT_WINDOW_TEXT)->get_root_coords(activation_rectangle_x, activation_rectangle.get_y(), root_x, root_y); }
Gdk::Rectangle rectangle; Gdk::Rectangle rectangle;
rectangle.set_x(root_x); rectangle.set_x(root_x);
rectangle.set_y(std::max(0, root_y-size.second)); rectangle.set_y(std::max(0, root_y-size.second));

5
src/tooltips.h

@ -6,7 +6,8 @@
class Tooltip { class Tooltip {
public: public:
Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark); Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark);
Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer) : Tooltip(create_tooltip_buffer, nullptr, Glib::RefPtr<Gtk::TextBuffer::Mark>(), Glib::RefPtr<Gtk::TextBuffer::Mark>()) {}
~Tooltip(); ~Tooltip();
void update(); void update();
@ -22,7 +23,7 @@ private:
std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer; std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer;
std::unique_ptr<Gtk::TextView> tooltip_widget; std::unique_ptr<Gtk::TextView> tooltip_widget;
Gtk::TextView& text_view; Gtk::TextView *text_view;
std::pair<int, int> size; std::pair<int, int> size;
std::pair<int, int> position; std::pair<int, int> position;
}; };

119
src/window.cc

@ -9,6 +9,7 @@
#include "entrybox.h" #include "entrybox.h"
#include "info.h" #include "info.h"
#include "ctags.h" #include "ctags.h"
#include "selection_dialog.h"
namespace sigc { namespace sigc {
#ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE #ifndef SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE
@ -573,48 +574,62 @@ void Window::set_menu_actions() {
}); });
menu.add_action("source_find_symbol_ctags", [this]() { menu.add_action("source_find_symbol_ctags", [this]() {
if(auto view=Notebook::get().get_current_view()) { auto view=Notebook::get().get_current_view();
auto pair=Ctags::get_result(view->file_path.parent_path());
auto path=std::move(pair.first); boost::filesystem::path ctags_path;
auto stream=std::move(pair.second); if(view)
stream->seekg(0, std::ios::end); ctags_path=view->file_path.parent_path();
if(stream->tellg()==0) { else if(!Directories::get().path.empty())
Info::get().print("No symbols found in current project"); ctags_path=Directories::get().path;
return; else
} ctags_path=boost::filesystem::current_path();
stream->seekg(0, std::ios::beg); auto pair=Ctags::get_result(ctags_path);
auto path=std::move(pair.first);
auto stream=std::move(pair.second);
stream->seekg(0, std::ios::end);
if(stream->tellg()==0) {
Info::get().print("No symbols found in current project");
return;
}
stream->seekg(0, std::ios::beg);
if(view) {
auto dialog_iter=view->get_iter_for_dialog(); auto dialog_iter=view->get_iter_for_dialog();
view->selection_dialog=std::make_unique<SelectionDialog>(*view, view->get_buffer()->create_mark(dialog_iter), true, true); SelectionDialog::create(view, view->get_buffer()->create_mark(dialog_iter), true, true);
auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >(); }
else
SelectionDialog::create(true, true);
std::string line; auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >();
while(std::getline(*stream, line)) {
auto location=Ctags::get_location(line, true);
std::string row=location.file_path.string()+":"+std::to_string(location.line+1)+": "+location.source; std::string line;
(*rows)[row]=Source::Offset(location.line, location.index, location.file_path); while(std::getline(*stream, line)) {
view->selection_dialog->add_row(row); auto location=Ctags::get_location(line, true);
}
if(rows->size()==0) std::string row=location.file_path.string()+":"+std::to_string(location.line+1)+": "+location.source;
(*rows)[row]=Source::Offset(location.line, location.index, location.file_path);
SelectionDialog::get()->add_row(row);
}
if(rows->size()==0)
return;
SelectionDialog::get()->on_select=[this, rows, path](const std::string &selected, bool hide_window) {
auto offset=rows->at(selected);
boost::filesystem::path declaration_file;
boost::system::error_code ec;
declaration_file=boost::filesystem::canonical(path/offset.file_path, ec);
if(ec)
return; return;
view->selection_dialog->on_select=[this, rows, path](const std::string &selected, bool hide_window) { Notebook::get().open(declaration_file);
auto offset=rows->at(selected); auto view=Notebook::get().get_current_view();
boost::filesystem::path declaration_file; view->place_cursor_at_line_index(offset.line, offset.index);
boost::system::error_code ec; view->scroll_to_cursor_delayed(view, true, false);
declaration_file=boost::filesystem::canonical(path/offset.file_path, ec);
if(ec)
return;
Notebook::get().open(declaration_file);
auto view=Notebook::get().get_current_view();
view->place_cursor_at_line_index(offset.line, offset.index);
view->scroll_to_cursor_delayed(view, true, false);
view->hide_tooltips();
};
view->hide_tooltips(); view->hide_tooltips();
view->selection_dialog->show(); };
} if(view)
view->hide_tooltips();
SelectionDialog::get()->show();
}); });
menu.add_action("source_comments_toggle", [this]() { menu.add_action("source_comments_toggle", [this]() {
@ -698,7 +713,7 @@ void Window::set_menu_actions() {
auto locations=view->get_implementation_locations(Notebook::get().get_views()); auto locations=view->get_implementation_locations(Notebook::get().get_views());
if(!locations.empty()) { if(!locations.empty()) {
auto dialog_iter=view->get_iter_for_dialog(); auto dialog_iter=view->get_iter_for_dialog();
view->selection_dialog=std::make_unique<SelectionDialog>(*view, view->get_buffer()->create_mark(dialog_iter), true, true); SelectionDialog::create(view, view->get_buffer()->create_mark(dialog_iter), true, true);
auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >(); auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >();
auto project_path=Project::Build::create(view->file_path)->project_path; auto project_path=Project::Build::create(view->file_path)->project_path;
if(project_path.empty()) { if(project_path.empty()) {
@ -718,7 +733,7 @@ void Window::set_menu_actions() {
path=location.file_path.filename(); path=location.file_path.filename();
auto row=path.string()+":"+std::to_string(location.line+1); auto row=path.string()+":"+std::to_string(location.line+1);
(*rows)[row]=location; (*rows)[row]=location;
view->selection_dialog->add_row(row); SelectionDialog::get()->add_row(row);
} }
} }
@ -734,7 +749,7 @@ void Window::set_menu_actions() {
view->scroll_to_cursor_delayed(view, true, false); view->scroll_to_cursor_delayed(view, true, false);
return; return;
} }
view->selection_dialog->on_select=[this, rows](const std::string &selected, bool hide_window) { SelectionDialog::get()->on_select=[this, rows](const std::string &selected, bool hide_window) {
auto location=rows->at(selected); auto location=rows->at(selected);
Notebook::get().open(location.file_path); Notebook::get().open(location.file_path);
auto view=Notebook::get().get_current_view(); auto view=Notebook::get().get_current_view();
@ -743,7 +758,7 @@ void Window::set_menu_actions() {
view->hide_tooltips(); view->hide_tooltips();
}; };
view->hide_tooltips(); view->hide_tooltips();
view->selection_dialog->show(); SelectionDialog::get()->show();
} }
} }
} }
@ -755,7 +770,7 @@ void Window::set_menu_actions() {
auto usages=view->get_usages(Notebook::get().get_views()); auto usages=view->get_usages(Notebook::get().get_views());
if(!usages.empty()) { if(!usages.empty()) {
auto dialog_iter=view->get_iter_for_dialog(); auto dialog_iter=view->get_iter_for_dialog();
view->selection_dialog=std::make_unique<SelectionDialog>(*view, view->get_buffer()->create_mark(dialog_iter), true, true); SelectionDialog::create(view, view->get_buffer()->create_mark(dialog_iter), true, true);
auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >(); auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >();
auto iter=view->get_buffer()->get_insert()->get_iter(); auto iter=view->get_buffer()->get_insert()->get_iter();
@ -769,18 +784,18 @@ void Window::set_menu_actions() {
} }
row+=std::to_string(usage.first.line+1)+": "+usage.second; row+=std::to_string(usage.first.line+1)+": "+usage.second;
(*rows)[row]=usage.first; (*rows)[row]=usage.first;
view->selection_dialog->add_row(row); SelectionDialog::get()->add_row(row);
//Set dialog cursor to the last row if the textview cursor is at the same line //Set dialog cursor to the last row if the textview cursor is at the same line
if(current_page && if(current_page &&
iter.get_line()==static_cast<int>(usage.first.line) && iter.get_line_index()>=static_cast<int>(usage.first.index)) { iter.get_line()==static_cast<int>(usage.first.line) && iter.get_line_index()>=static_cast<int>(usage.first.index)) {
view->selection_dialog->set_cursor_at_last_row(); SelectionDialog::get()->set_cursor_at_last_row();
} }
} }
if(rows->size()==0) if(rows->size()==0)
return; return;
view->selection_dialog->on_select=[this, rows](const std::string &selected, bool hide_window) { SelectionDialog::get()->on_select=[this, rows](const std::string &selected, bool hide_window) {
auto offset=rows->at(selected); auto offset=rows->at(selected);
boost::filesystem::path declaration_file; boost::filesystem::path declaration_file;
boost::system::error_code ec; boost::system::error_code ec;
@ -794,7 +809,7 @@ void Window::set_menu_actions() {
view->hide_tooltips(); view->hide_tooltips();
}; };
view->hide_tooltips(); view->hide_tooltips();
view->selection_dialog->show(); SelectionDialog::get()->show();
} }
} }
} }
@ -805,23 +820,23 @@ void Window::set_menu_actions() {
auto methods=Notebook::get().get_current_view()->get_methods(); auto methods=Notebook::get().get_current_view()->get_methods();
if(!methods.empty()) { if(!methods.empty()) {
auto dialog_iter=view->get_iter_for_dialog(); auto dialog_iter=view->get_iter_for_dialog();
view->selection_dialog=std::make_unique<SelectionDialog>(*view, view->get_buffer()->create_mark(dialog_iter), true, true); SelectionDialog::create(view, view->get_buffer()->create_mark(dialog_iter), true, true);
auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >(); auto rows=std::make_shared<std::unordered_map<std::string, Source::Offset> >();
auto iter=view->get_buffer()->get_insert()->get_iter(); auto iter=view->get_buffer()->get_insert()->get_iter();
for(auto &method: methods) { for(auto &method: methods) {
(*rows)[method.second]=method.first; (*rows)[method.second]=method.first;
view->selection_dialog->add_row(method.second); SelectionDialog::get()->add_row(method.second);
if(iter.get_line()>=static_cast<int>(method.first.line)) if(iter.get_line()>=static_cast<int>(method.first.line))
view->selection_dialog->set_cursor_at_last_row(); SelectionDialog::get()->set_cursor_at_last_row();
} }
view->selection_dialog->on_select=[view, rows](const std::string& selected, bool hide_window) { SelectionDialog::get()->on_select=[view, rows](const std::string& selected, bool hide_window) {
auto offset=rows->at(selected); auto offset=rows->at(selected);
view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(offset.line, offset.index)); view->get_buffer()->place_cursor(view->get_buffer()->get_iter_at_line_index(offset.line, offset.index));
view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5); view->scroll_to(view->get_buffer()->get_insert(), 0.0, 1.0, 0.5);
view->hide_tooltips(); view->hide_tooltips();
}; };
view->hide_tooltips(); view->hide_tooltips();
view->selection_dialog->show(); SelectionDialog::get()->show();
} }
} }
} }
@ -1150,7 +1165,6 @@ void Window::activate_menu_items() {
menu.actions["source_center_cursor"]->set_enabled(view); menu.actions["source_center_cursor"]->set_enabled(view);
menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(view && static_cast<bool>(view->format_style)); menu.actions["source_indentation_auto_indent_buffer"]->set_enabled(view && static_cast<bool>(view->format_style));
menu.actions["source_find_symbol_ctags"]->set_enabled(view);
menu.actions["source_comments_toggle"]->set_enabled(view && static_cast<bool>(view->toggle_comments)); menu.actions["source_comments_toggle"]->set_enabled(view && static_cast<bool>(view->toggle_comments));
menu.actions["source_comments_add_documentation"]->set_enabled(view && static_cast<bool>(view->add_documentation)); menu.actions["source_comments_add_documentation"]->set_enabled(view && static_cast<bool>(view->add_documentation));
menu.actions["source_find_documentation"]->set_enabled(view && static_cast<bool>(view->get_token_data)); menu.actions["source_find_documentation"]->set_enabled(view && static_cast<bool>(view->get_token_data));
@ -1198,6 +1212,11 @@ bool Window::on_key_press_event(GdkEventKey *event) {
} }
#endif #endif
if(SelectionDialog::get() && SelectionDialog::get()->is_visible()) {
if(SelectionDialog::get()->on_key_press(event))
return true;
}
return Gtk::ApplicationWindow::on_key_press_event(event); return Gtk::ApplicationWindow::on_key_press_event(event);
} }

2
tests/CMakeLists.txt

@ -5,7 +5,7 @@ set(stub_files
stubs/dialogs.cc stubs/dialogs.cc
stubs/directories.cc stubs/directories.cc
stubs/info.cc stubs/info.cc
stubs/selectiondialog.cc stubs/selection_dialog.cc
stubs/terminal.cc stubs/terminal.cc
stubs/tooltips.cc stubs/tooltips.cc
) )

12
tests/stubs/selectiondialog.cc → tests/stubs/selection_dialog.cc

@ -1,8 +1,8 @@
#include "selectiondialog.h" #include "selection_dialog.h"
SelectionDialogBase::ListViewText::ListViewText(bool use_markup) {} SelectionDialogBase::ListViewText::ListViewText(bool use_markup) {}
SelectionDialogBase::SelectionDialogBase(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup): SelectionDialogBase::SelectionDialogBase(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup):
text_view(text_view), list_view_text(use_markup) {} text_view(text_view), list_view_text(use_markup) {}
void SelectionDialogBase::show() {} void SelectionDialogBase::show() {}
@ -11,14 +11,18 @@ void SelectionDialogBase::hide() {}
void SelectionDialogBase::add_row(const std::string& row) {} void SelectionDialogBase::add_row(const std::string& row) {}
SelectionDialog::SelectionDialog(Gtk::TextView& text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup) : std::unique_ptr<SelectionDialog> SelectionDialog::instance;
SelectionDialog::SelectionDialog(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, bool show_search_entry, bool use_markup) :
SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {} SelectionDialogBase(text_view, start_mark, show_search_entry, use_markup) {}
SelectionDialogBase::~SelectionDialogBase() {} SelectionDialogBase::~SelectionDialogBase() {}
bool SelectionDialog::on_key_press(GdkEventKey* key) { return true; } bool SelectionDialog::on_key_press(GdkEventKey* key) { return true; }
CompletionDialog::CompletionDialog(Gtk::TextView &text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark): std::unique_ptr<CompletionDialog> CompletionDialog::instance;
CompletionDialog::CompletionDialog(Gtk::TextView *text_view, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark):
SelectionDialogBase(text_view, start_mark, false, false) {} SelectionDialogBase(text_view, start_mark, false, false) {}
bool CompletionDialog::on_key_press(GdkEventKey* key) { return true;} bool CompletionDialog::on_key_press(GdkEventKey* key) { return true;}

2
tests/stubs/tooltips.cc

@ -3,7 +3,7 @@
Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle(); Gdk::Rectangle Tooltips::drawn_tooltips_rectangle=Gdk::Rectangle();
Tooltip::Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer, Tooltip::Tooltip(std::function<Glib::RefPtr<Gtk::TextBuffer>()> create_tooltip_buffer,
Gtk::TextView& text_view, Gtk::TextView *text_view,
Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark, Glib::RefPtr<Gtk::TextBuffer::Mark> start_mark,
Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark): text_view(text_view) {} Glib::RefPtr<Gtk::TextBuffer::Mark> end_mark): text_view(text_view) {}

Loading…
Cancel
Save