diff --git a/FL/Fl_Help_View.H b/FL/Fl_Help_View.H index 6f19a9a54..b6b21cc97 100644 --- a/FL/Fl_Help_View.H +++ b/FL/Fl_Help_View.H @@ -235,20 +235,20 @@ class FL_EXPORT Fl_Help_View : public Fl_Group { // Help viewer widget Fl_Scrollbar scrollbar_, ///< Vertical scrollbar for document hscrollbar_; ///< Horizontal scrollbar - static int selection_first; - static int selection_last; - static int selection_push_first; - static int selection_push_last; - static int selection_drag_first; - static int selection_drag_last; - static int selected; - static int draw_mode; - static int mouse_x; - static int mouse_y; - static int current_pos; - static Fl_Help_View *current_view; - static Fl_Color hv_selection_color; - static Fl_Color hv_selection_text_color; + static int selection_first_; + static int selection_last_; + static int selection_push_first_; + static int selection_push_last_; + static int selection_drag_first_; + static int selection_drag_last_; + static int selected_; + static int draw_mode_; + static int mouse_x_; + static int mouse_y_; + static int current_pos_; + static Fl_Help_View *current_view_; + static Fl_Color hv_selection_color_; + static Fl_Color hv_selection_text_color_; void initfont(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c) { f = textfont_; s = textsize_; c = textcolor_; fstack_.init(f, s, c); } @@ -286,6 +286,8 @@ private: public: + static const char *copy_menu_text; + Fl_Help_View(int xx, int yy, int ww, int hh, const char *l = 0); ~Fl_Help_View(); /** Returns the current directory for the text in the buffer. */ @@ -383,6 +385,12 @@ public: void scrollbar_size(int newSize) { scrollbar_size_ = newSize; } + + // Check if the user selected text in this view. + int text_selected(); + + // If text is selected in this view, copy it to a clipboard. + int copy(int clipboard=1); }; #endif // !Fl_Help_View_H diff --git a/src/Fl_Help_View.cxx b/src/Fl_Help_View.cxx index f83c8a126..d77d5caee 100644 --- a/src/Fl_Help_View.cxx +++ b/src/Fl_Help_View.cxx @@ -50,6 +50,7 @@ #include #include #include +#include #include "Fl_Int_Vector.H" #include "Fl_String.H" @@ -130,6 +131,14 @@ static const char * const broken_xpm[] = static Fl_Pixmap broken_image(broken_xpm); +/** [this text may be customized at run-time] */ +const char *Fl_Help_View::copy_menu_text = "Copy"; + +static Fl_Menu_Item rmb_menu[] = { + { NULL, 0, NULL, (void*)1 }, // Copy + { NULL } +}; + // // Simple margin stack for Fl_Help_View::format()... // @@ -210,51 +219,51 @@ img->draw() // We don't put the offscreen buffer in the help view class because // we'd need to include platform.H in the header... static Fl_Offscreen fl_help_view_buffer; -int Fl_Help_View::selection_first = 0; -int Fl_Help_View::selection_last = 0; -int Fl_Help_View::selection_push_first = 0; -int Fl_Help_View::selection_push_last = 0; -int Fl_Help_View::selection_drag_first = 0; -int Fl_Help_View::selection_drag_last = 0; -int Fl_Help_View::selected = 0; -int Fl_Help_View::draw_mode = 0; -int Fl_Help_View::mouse_x = 0; -int Fl_Help_View::mouse_y = 0; -int Fl_Help_View::current_pos = 0; -Fl_Help_View *Fl_Help_View::current_view = 0L; -Fl_Color Fl_Help_View::hv_selection_color; -Fl_Color Fl_Help_View::hv_selection_text_color; +int Fl_Help_View::selection_first_ = 0; +int Fl_Help_View::selection_last_ = 0; +int Fl_Help_View::selection_push_first_ = 0; +int Fl_Help_View::selection_push_last_ = 0; +int Fl_Help_View::selection_drag_first_ = 0; +int Fl_Help_View::selection_drag_last_ = 0; +int Fl_Help_View::selected_ = 0; +int Fl_Help_View::draw_mode_ = 0; +int Fl_Help_View::mouse_x_ = 0; +int Fl_Help_View::mouse_y_ = 0; +int Fl_Help_View::current_pos_ = 0; +Fl_Help_View *Fl_Help_View::current_view_ = 0L; +Fl_Color Fl_Help_View::hv_selection_color_; +Fl_Color Fl_Help_View::hv_selection_text_color_; /* * This function must be optimized for speed! */ void Fl_Help_View::hv_draw(const char *t, int x, int y, int entity_extra_length) { - if (selected && current_view==this && current_pos=selection_first) { + if (selected_ && current_view_==this && current_pos_=selection_first_) { Fl_Color c = fl_color(); - fl_color(hv_selection_color); + fl_color(hv_selection_color_); int w = (int)fl_width(t); - if (current_pos+(int)strlen(t)=x && mouse_x=y-fl_height()+fl_descent()&&mouse_y<=y+fl_descent()) { - int f = (int) current_pos; + if (mouse_x_>=x && mouse_x_=y-fl_height()+fl_descent()&&mouse_y_<=y+fl_descent()) { + int f = (int) current_pos_; int l = (int) (f+strlen(t)); // use 'quote_char' to calculate the true length of the HTML string - if (draw_mode==1) { - selection_push_first = f; - selection_push_last = l; + if (draw_mode_==1) { + selection_push_first_ = f; + selection_push_last_ = l; } else { - selection_drag_first = f; - selection_drag_last = l + entity_extra_length; + selection_drag_first_ = f; + selection_drag_last_ = l + entity_extra_length; } } } @@ -556,11 +565,11 @@ Fl_Help_View::draw() if (!value_) return; - if (current_view == this && selected) { - hv_selection_color = FL_SELECTION_COLOR; - hv_selection_text_color = fl_contrast(textcolor_, FL_SELECTION_COLOR); + if (current_view_ == this && selected_) { + hv_selection_color_ = FL_SELECTION_COLOR; + hv_selection_text_color_ = fl_contrast(textcolor_, FL_SELECTION_COLOR); } - current_pos = 0; + current_pos_ = 0; // Clip the drawing to the inside of the box... fl_push_clip(x() + Fl::box_dx(b), y() + Fl::box_dy(b), @@ -613,7 +622,7 @@ Fl_Help_View::draw() fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + ww + xtra_ww); } - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); xx += ww; if ((fsize + 2) > hh) @@ -631,7 +640,7 @@ Fl_Help_View::draw() if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + buf.width()); buf.clear(); - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); if (line < 31) line ++; xx = block->line[line]; @@ -662,7 +671,7 @@ Fl_Help_View::draw() if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + ww); xx += ww; - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } needspace = 0; @@ -673,7 +682,7 @@ Fl_Help_View::draw() while (isspace((*ptr)&255)) ptr ++; - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } } @@ -705,7 +714,7 @@ Fl_Help_View::draw() ptr ++; // end of command reached, set the supposed start of printed eord here - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); if (buf.cmp("HEAD")) head = 1; else if (buf.cmp("BR")) @@ -964,7 +973,7 @@ Fl_Help_View::draw() needspace = 0; ptr ++; - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } else if (isspace((*ptr)&255)) { @@ -982,7 +991,7 @@ Fl_Help_View::draw() } ptr ++; - if (!pre) current_pos = (int) (ptr-value_); + if (!pre) current_pos_ = (int) (ptr-value_); needspace = 1; } else if (*ptr == '&') // process html entity @@ -1036,7 +1045,7 @@ Fl_Help_View::draw() hv_draw(buf.c_str(), xx + x() - leftline_, yy + y()); if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + ww); - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } } @@ -2837,7 +2846,7 @@ void Fl_Help_View::follow_link(Fl_Help_Link *linkp) /** Removes the current text selection. */ void Fl_Help_View::clear_selection() { - if (current_view==this) + if (current_view_==this) clear_global_selection(); } /** Selects all the text in the view. */ @@ -2845,18 +2854,18 @@ void Fl_Help_View::select_all() { clear_global_selection(); if (!value_) return; - current_view = this; - selection_drag_last = selection_last = (int) strlen(value_); - selected = 1; + current_view_ = this; + selection_drag_last_ = selection_last_ = (int) strlen(value_); + selected_ = 1; } void Fl_Help_View::clear_global_selection() { - if (selected) redraw(); - selection_push_first = selection_push_last = 0; - selection_drag_first = selection_drag_last = 0; - selection_first = selection_last = 0; - selected = 0; + if (selected_) redraw(); + selection_push_first_ = selection_push_last_ = 0; + selection_drag_first_ = selection_drag_last_ = 0; + selection_first_ = selection_last_ = 0; + selected_ = 0; } char Fl_Help_View::begin_selection() @@ -2865,18 +2874,18 @@ char Fl_Help_View::begin_selection() if (!fl_help_view_buffer) fl_help_view_buffer = fl_create_offscreen(1, 1); - mouse_x = Fl::event_x(); - mouse_y = Fl::event_y(); - draw_mode = 1; + mouse_x_ = Fl::event_x(); + mouse_y_ = Fl::event_y(); + draw_mode_ = 1; - current_view = this; + current_view_ = this; fl_begin_offscreen(fl_help_view_buffer); draw(); fl_end_offscreen(); - draw_mode = 0; + draw_mode_ = 0; - if (selection_push_last) return 1; + if (selection_push_last_) return 1; else return 0; } @@ -2885,38 +2894,44 @@ char Fl_Help_View::extend_selection() if (Fl::event_is_click()) return 0; -// printf("old selection_first=%d, selection_last=%d\n", -// selection_first, selection_last); + // Give this widget the focus during the selection process. This will + // deselect other text selection and make sure, we receive the Copy + // keyboard shortcut. + if (Fl::focus()!=this) + Fl::focus(this); - int sf = selection_first, sl = selection_last; +// printf("old selection_first_=%d, selection_last_=%d\n", +// selection_first_, selection_last_); - selected = 1; - mouse_x = Fl::event_x(); - mouse_y = Fl::event_y(); - draw_mode = 2; + int sf = selection_first_, sl = selection_last_; + + selected_ = 1; + mouse_x_ = Fl::event_x(); + mouse_y_ = Fl::event_y(); + draw_mode_ = 2; fl_begin_offscreen(fl_help_view_buffer); draw(); fl_end_offscreen(); - draw_mode = 0; + draw_mode_ = 0; - if (selection_push_first < selection_drag_first) { - selection_first = selection_push_first; + if (selection_push_first_ < selection_drag_first_) { + selection_first_ = selection_push_first_; } else { - selection_first = selection_drag_first; + selection_first_ = selection_drag_first_; } - if (selection_push_last > selection_drag_last) { - selection_last = selection_push_last; + if (selection_push_last_ > selection_drag_last_) { + selection_last_ = selection_push_last_; } else { - selection_last = selection_drag_last; + selection_last_ = selection_drag_last_; } -// printf("new selection_first=%d, selection_last=%d\n", -// selection_first, selection_last); +// printf("new selection_first_=%d, selection_last_=%d\n", +// selection_first_, selection_last_); - if (sf!=selection_first || sl!=selection_last) { + if (sf!=selection_first_ || sl!=selection_last_) { // puts("REDRAW!!!\n"); return 1; } else { @@ -2947,7 +2962,7 @@ static unsigned int command(const char *cmd) void Fl_Help_View::end_selection(int clipboard) { - if (!selected || current_view!=this) + if (!selected_ || current_view_!=this) return; // convert the select part of our html text into some kind of somewhat readable UTF-8 // and store it in the selection buffer @@ -2995,7 +3010,7 @@ void Fl_Help_View::end_selection(int clipboard) case CMD('d','d', 0 , 0 ): src = "\n - "; break; } int n = (int) (s-value_); - if (src && n>selection_first && n<=selection_last) { + if (src && n>selection_first_ && n<=selection_last_) { while (*src) { *d++ = *src++; } @@ -3016,7 +3031,7 @@ void Fl_Help_View::end_selection(int clipboard) } } int n = (int) (s2-value_); - if (n>selection_first && n<=selection_last) { + if (n>selection_first_ && n<=selection_last_) { if (!pre && c < 256 && isspace(c)) c = ' '; if (p != ' ' || c != ' ') { if (s2 != s) { // c was an HTML entity @@ -3026,7 +3041,7 @@ void Fl_Help_View::end_selection(int clipboard) } p = c; } - if (n>selection_last) break; // stop parsing html after end of selection + if (n>selection_last_) break; // stop parsing html after end of selection } *d = 0; Fl::copy(txt, (int) strlen(txt), clipboard); @@ -3034,6 +3049,31 @@ void Fl_Help_View::end_selection(int clipboard) free(txt); } +/** + \brief Check if the user selected text in this view. + \return 1 if text is selected, 0 if no text is selected + */ +int Fl_Help_View::text_selected() { + if (current_view_==this) + return selected_; + else + return 0; +} + +/** + \brief If text is selected in this view, copy it to a clipboard. + \param[in] clipboard for x11 only, 0=selection buffer, 1=clipboard, 2=both + \return 1 if text is selected, 0 if no text is selected + */ +int Fl_Help_View::copy(int clipboard) { + if (text_selected()) { + end_selection(clipboard); + return 1; + } else { + return 0; + } +} + /** Handles events in the widget. */ int // O - 1 if we handled it, 0 otherwise Fl_Help_View::handle(int event) // I - Event to handle @@ -3063,6 +3103,20 @@ Fl_Help_View::handle(int event) // I - Event to handle else fl_cursor(FL_CURSOR_DEFAULT); return 1; case FL_PUSH: + if (Fl::event_button() == FL_RIGHT_MOUSE) { + rmb_menu[0].label(copy_menu_text); + if (text_selected()) + rmb_menu[0].activate(); + else + rmb_menu[0].deactivate(); + fl_cursor(FL_CURSOR_DEFAULT); + const Fl_Menu_Item *mi = rmb_menu->popup(Fl::event_x(), Fl::event_y()); + if (mi) switch (mi->argument()) { + case 1: + copy(); + break; + } + } if (Fl_Group::handle(event)) return 1; linkp = find_link(xx, yy); if (linkp) { @@ -3084,7 +3138,7 @@ Fl_Help_View::handle(int event) // I - Event to handle } return 1; } - if (current_view==this && selection_push_last) { + if (current_view_==this && selection_push_last_) { if (extend_selection()) redraw(); fl_cursor(FL_CURSOR_INSERT); return 1; @@ -3100,7 +3154,7 @@ Fl_Help_View::handle(int event) // I - Event to handle linkp = 0; return 1; } - if (current_view==this && selection_push_last) { + if (current_view_==this && selection_push_last_) { end_selection(); return 1; }