#pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nlohmann/json.hpp" #include "DocumentThread.hh" #include "ComputeThread.hh" #include "Console.hh" #include "GUIBase.hh" #include "NotebookCanvas.hh" #include "../common/TeXEngine.hh" #include "DiffViewer.hh" class Cadabra; namespace cadabra { /// \ingroup frontend /// /// Each notebook has one main window which controls it. It has a menu bar, a /// status pane and one or more panels that represent a view on the document. class NotebookWindow : public Gtk::ApplicationWindow, public DocumentThread, public GUIBase { public: NotebookWindow(Cadabra *, bool read_only=false); ~NotebookWindow(); // Virtual functions from GUIBase. virtual void add_cell(const DTree&, DTree::iterator, bool) override; virtual void remove_cell(const DTree&, DTree::iterator) override; virtual void remove_all_cells() override; virtual void update_cell(const DTree&, DTree::iterator) override; virtual void position_cursor(const DTree&, DTree::iterator, int pos) override; virtual size_t get_cursor_position(const DTree&, DTree::iterator) override; void select_range(const DTree&, DTree::iterator, int start, int len); virtual void on_connect() override; virtual void on_disconnect(const std::string&) override; virtual void on_network_error() override; virtual void on_kernel_runstatus(bool) override; virtual void process_data() override; // TeX stuff TeXEngine engine; double scale; // total scale factor (hdpi and textscale) double display_scale; // hdpi scale only // Handler for vertical scrollbar changes. bool on_vscroll_changed(Gtk::ScrollType, double); // Handler for mouse wheel events. // bool on_mouse_wheel(GdkEventButton*); // Handler for scroll events. bool on_scroll(GdkEventScroll*); // When something inside the large notebook canvas changes, we need // to make sure that the current cell stays into view (if we are // editing that cell). We can only do that once all size info is // known, which is when the scrolledwindow gets its size_allocate // signal. Here's the handler for it. void on_scroll_size_allocate(Gtk::Allocation&); // Ensure that the current cell is visible. This will assume // that all size allocations of widgets inside the scrolled window // have been made; it only does scrolling, based on the current // allocations. Calls `scroll_cell_into_view`. void scroll_current_cell_into_view(); // Ensure that the indicated cell is visible. void scroll_cell_into_view(DTree::iterator cell); void set_name(const std::string&); void set_title_prefix(const std::string&); void load_file(const std::string& notebook_contents); void refresh_highlighting(); void on_help_register(); void set_statusbar_message(const std::string& message = "", int line = -1, int col = -1); /// Functionality for the diff viewer. void select_git_path(); void compare_to_file(); void compare_git_latest(); void compare_git_choose(); void compare_git_specific(); void compare_git(const std::string& commit_hash); std::string run_git_command(const std::string& args); virtual void set_compute_thread(ComputeThread* compute) override; virtual void on_interactive_output(const nlohmann::json& msg) override; virtual void set_progress(const std::string& msg, int cur_step, int total_steps) override; protected: virtual bool on_key_press_event(GdkEventKey*) override; virtual bool on_delete_event(GdkEventAny*) override; virtual bool on_configure_event(GdkEventConfigure *cfg) override; virtual bool on_unhandled_error(const std::exception& err) override; DTree::iterator current_cell; bool handle_outbox_select(GdkEventButton *, DTree::iterator it); DTree::iterator selected_cell; void unselect_output_cell(); void on_outbox_copy(Glib::RefPtr refClipboard, DTree::iterator it); private: Glib::RefPtr cdbapp; std::vector> default_actions; // Main handler which fires whenever the Client object signals // that the document is changing or the network status is modified. // Runs on the GUI thread. Glib::Dispatcher dispatcher; // GUI elements. Glib::RefPtr actiongroup; Glib::RefPtr uimanager; Gtk::VBox topbox; Gtk::HBox toolbar; Gtk::Button tool_open, tool_save, tool_save_as; Gtk::Button tool_run, tool_run_to, tool_stop, tool_restart; Gtk::HBox supermainbox; Gtk::Paned dragbox; Gtk::VBox mainbox; // Gtk::HBox buttonbox; Gtk::SearchBar searchbar; Gtk::HBox search_hbox; Gtk::SearchEntry searchentry; Gtk::CheckButton search_case_insensitive; Gtk::Label search_result; Gtk::HBox statusbarbox; Console console; Gtk::Dialog console_win; std::unique_ptr diffviewer; // All canvasses which are stored in the ... // These pointers are managed by gtkmm. std::vector canvasses; int current_canvas; // Buttons // Gtk::Button b_kill, b_run, b_run_to, b_run_from, b_help, b_stop, b_undo, b_redo; // Status bar Gtk::ProgressBar progressbar; Gtk::Spinner kernel_spinner; bool kernel_spinner_status; Gtk::Label status_label, kernel_label, top_label; // GUI data which is the autoritative source for things displayed in // the status bars declared above. These strings are filled on the // compute thread and then updated into the gui on the gui thread. std::mutex status_mutex; std::string status_string, kernel_string, progress_string; double progress_frac; int status_line, status_col; Glib::Dispatcher dispatch_update_status, dispatch_refresh, dispatch_tex_error; void update_status(); // Run the TeX engine on a separate thread, then call // `dispatch_refresh` to update the display. void tex_run_async(); // Name and modification data. void update_title(); void set_stop_sensitive(bool); std::string name, title_prefix; bool modified, read_only; // Menu and button callbacks. void on_file_new(); void on_file_open(); void on_file_close(); void on_file_save(); void on_file_save_as(); void on_file_save_as_jupyter(); void on_file_export_html(); void on_file_export_html_segment(); void on_file_export_latex(); void on_file_export_python(); void on_file_quit(); bool quit_safeguard(bool quit); bool on_first_redraw(); void on_edit_undo(); void on_edit_copy(const Glib::VariantBase&); void on_edit_paste(); void on_edit_insert_above(); void on_edit_insert_below(); void on_edit_delete(); void on_edit_split(); void on_edit_cell_is_latex(); void on_edit_cell_is_python(); void on_ignore_cell_on_import(); void on_edit_find(); void on_view_split(); void on_view_close(); void on_run_cell(); void on_run_runall(); void on_run_runtocursor(); void on_run_stop(); void on_prefs_set_cv(int vis); void on_prefs_font_size(int num); void on_prefs_highlight_syntax(bool on); void on_prefs_microtex(bool on); void on_prefs_choose_colours(); void on_prefs_use_defaults(); void on_tools_options(); void on_tools_clear_cache(); void on_help_about(); void on_help() const; void on_kernel_restart(); /// Search handling. void on_search_text_changed(); /// Clipboard handling void on_clipboard_get(Gtk::SelectionData&, guint info); void on_clipboard_clear(); std::string clipboard_txt, clipboard_cdb; // FIXME: move to DocumentThread std::string save(const std::string& fn) const; /// Todo deque processing logic. This gets called by the dispatcher, but it /// is also allowed to call this from within NotebookWindow itself. The important /// thing is that it is run on the GUI thread. void process_todo_queue(); /// Refresh the display after a TeX engine run has completed. The TeX /// engine is run on a different thread so as to not block the UI, and /// on completion triggers `dispatcher_refresh`, which calls this function /// on the main thread. void refresh_after_tex_engine_run(); /// Handle a TeX error which occurred on a threaded TeX run (activated by /// `tex_run_async`) and is stored in `tex_error_string`. void handle_thread_tex_error(); void on_crash_window_closed(int); bool crash_window_hidden; // The following are handlers that get called when the cell // gets focus, the content of a cell is changed, the user // requests to run it (shift-enter). The last two parameters are // always the cell in the DTree and the canvas number. bool cell_got_focus(DTree::iterator, int); bool cell_toggle_visibility(DTree::iterator it, int); bool cell_content_insert(const std::string&, int, DTree::iterator, int); bool cell_content_erase(int, int, DTree::iterator, int); bool cell_content_execute(DTree::iterator, int, bool shift_enter_pressed); bool cell_content_changed(DTree::iterator it, int i); bool cell_complete_request(DTree::iterator it, int pos, int i); void interactive_execute(); void dim_output_cells(DTree::iterator it); // Handler for callbacks from TeXView cells. bool on_tex_error(const std::string&, DTree::iterator); // Styling through CSS void load_css(); Glib::RefPtr css_provider; Glib::RefPtr settings; void on_text_scaling_factor_changed(const std::string& key); int last_configure_width; DTree::iterator follow_cell; // Mutex to protect the variables below. std::recursive_mutex tex_need_width_mutex; std::unique_ptr tex_thread; bool tex_running; int tex_need_width; std::string tex_error_string; std::pair last_find_location; std::string last_find_string; bool is_configured; // We keep references to a few menu actions so we can // enable/disable them at runtime. Glib::RefPtr action_copy, action_paste, action_fontsize, action_highlight, action_stop, action_register, action_console, action_microtex; // Transition animations. #if GTKMM_MINOR_VERSION>=10 std::vector to_reveal; #endif bool idle_handler(); }; };