/*************************************************************************** gtextarea.cpp (c) 2004-2006 - Daniel Campos Fernández Gtkmae "GTK+ made easy" classes Realizado para la Junta de Extremadura. Consejería de Educación Ciencia y Tecnología. Proyecto gnuLinEx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ***************************************************************************/ #include "widgets.h" #include "widgets_private.h" #include "gapplication.h" #include "gclipboard.h" #include "gtextarea.h" // Private structure took from GTK+ 2.10 code. Used for setting the text area cursor. // **** May not work on future GTK+ versions **** struct PrivateGtkTextWindow { GtkTextWindowType type; GtkWidget *widget; GdkWindow *window; GdkWindow *bin_window; GtkRequisition requisition; GdkRectangle allocation; }; // Private exported functions to get the size of the text // **** May not work on future GTK+ versions **** extern "C" { void gtk_text_layout_set_screen_width(struct _GtkTextLayout *layout, gint width); void gtk_text_layout_get_size(struct _GtkTextLayout *layout, gint *width, gint *height); void gtk_text_layout_invalidate (struct _GtkTextLayout *layout, const GtkTextIter *start, const GtkTextIter *end); void gtk_text_layout_validate (struct _GtkTextLayout *layout, gint max_pixels); } static gboolean cb_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gTextArea *data) { // Workaround GtkTextView internal cursor changes if (gApplication::isBusy()) data->setMouse(data->mouse()); return FALSE; } static void cb_changed(GtkTextBuffer *buf, gTextArea *data) { data->emit(SIGNAL(data->onChange)); } static void cb_mark_set(GtkTextBuffer *buf, GtkTextIter *location, GtkTextMark *mark, gTextArea *data) { if (mark == gtk_text_buffer_get_insert(buf)) data->emit(SIGNAL(data->onCursor)); } gTextArea::gTextArea(gContainer *parent) : gControl(parent) { GtkTextBuffer *buf; g_typ = Type_gTextArea; have_cursor = true; use_base = true; no_input_method = true; onChange = 0; onCursor = 0; border = gtk_scrolled_window_new (NULL,NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(border),GTK_POLICY_AUTOMATIC,GTK_POLICY_AUTOMATIC); widget = gtk_text_view_new(); realize(); g_signal_connect_after(G_OBJECT(widget), "motion-notify-event", G_CALLBACK(cb_motion_notify_event), (gpointer)this); buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); g_signal_connect_after(G_OBJECT(buf), "changed", G_CALLBACK(cb_changed), (gpointer)this); g_signal_connect_after(G_OBJECT(buf), "mark-set", G_CALLBACK(cb_mark_set), (gpointer)this); setBorder(true); setWrap(false); } bool gTextArea::hasBorder() { if (gtk_scrolled_window_get_shadow_type(GTK_SCROLLED_WINDOW(border))==GTK_SHADOW_NONE) return false; return true; } void gTextArea::setBorder(bool vl) { if (vl) gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(border),GTK_SHADOW_IN); else gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(border),GTK_SHADOW_NONE); } char* gTextArea::text() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start; GtkTextIter end; if (!buf) return NULL; gtk_text_buffer_get_bounds(buf,&start,&end); return gtk_text_buffer_get_text(buf,&start,&end,true); } void gTextArea::setText(const char *txt) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); if (!txt) txt=""; gtk_text_buffer_set_text(buf,(const gchar *)txt,-1); } bool gTextArea::readOnly() { return !gtk_text_view_get_editable(GTK_TEXT_VIEW(widget)); } void gTextArea::setReadOnly(bool vl) { gtk_text_view_set_editable(GTK_TEXT_VIEW(widget),!vl); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(widget),!vl); } int gTextArea::line() { GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextMark* mark = gtk_text_buffer_get_insert(buf); GtkTextIter iter; gtk_text_buffer_get_iter_at_mark(buf,&iter,mark); return gtk_text_iter_get_line(&iter); } void gTextArea::setLine(int vl) { int col=column(); GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextMark* mark=gtk_text_buffer_get_insert(buf); GtkTextIter iter; gtk_widget_grab_focus(widget); gtk_text_buffer_get_iter_at_mark(buf,&iter,mark); gtk_text_iter_set_line (&iter,vl); if (gtk_text_iter_get_chars_in_line (&iter)<=col) col=gtk_text_iter_get_chars_in_line (&iter)-1; gtk_text_iter_set_line_offset(&iter,col); gtk_text_buffer_place_cursor(buf,&iter); gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(widget),mark); } int gTextArea::column() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextMark* mark=gtk_text_buffer_get_insert(buf); GtkTextIter iter; gtk_text_buffer_get_iter_at_mark(buf,&iter,mark); return gtk_text_iter_get_line_offset(&iter); } void gTextArea::setColumn(int vl) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextMark* mark=gtk_text_buffer_get_insert(buf); GtkTextIter iter; gtk_widget_grab_focus(widget); gtk_text_buffer_get_iter_at_mark(buf,&iter,mark); if (vl<0) { vl=gtk_text_iter_get_chars_in_line (&iter)-1; } else { if (gtk_text_iter_get_chars_in_line (&iter)<=vl) vl=gtk_text_iter_get_chars_in_line (&iter)-1; } gtk_text_iter_set_line_offset(&iter,vl); gtk_text_buffer_place_cursor(buf,&iter); gtk_text_view_scroll_mark_onscreen(GTK_TEXT_VIEW(widget),mark); } int gTextArea::position() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextMark* mark=gtk_text_buffer_get_insert(buf); GtkTextIter iter; gtk_text_buffer_get_iter_at_mark(buf,&iter,mark); return gtk_text_iter_get_offset(&iter); } void gTextArea::setPosition(int vl) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextMark* mark=gtk_text_buffer_get_insert(buf); GtkTextIter iter; gtk_widget_grab_focus(widget); gtk_text_buffer_get_iter_at_mark(buf,&iter,mark); if (vl<0) { vl=gtk_text_iter_get_offset (&iter); } else { if (gtk_text_iter_get_offset (&iter)=length()) pos=length()-1; gtk_text_iter_set_offset(&iter,pos); return gtk_text_iter_get_line(&iter); } int gTextArea::toColumn(int pos) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter iter; gtk_text_buffer_get_start_iter(buf,&iter); if (pos<0) pos=0; if (pos>=length()) pos=length()-1; gtk_text_iter_set_offset(&iter,pos); return gtk_text_iter_get_line_offset(&iter); } int gTextArea::toPosition(int line,int col) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter iter; if (line<0) line=0; if (col<0) col=0; gtk_text_buffer_get_end_iter(buf,&iter); if (line>gtk_text_iter_get_line(&iter)) line=gtk_text_iter_get_line(&iter); gtk_text_iter_set_line(&iter,line); if (col>gtk_text_iter_get_line_offset(&iter)) col=gtk_text_iter_get_line_offset(&iter); gtk_text_iter_set_line_offset(&iter,col); return gtk_text_iter_get_offset(&iter); } /********************************************************************************** gTextArea selection ***********************************************************************************/ bool gTextArea::isSelected() { GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); return gtk_text_buffer_get_selection_bounds(buf,NULL,NULL); //return gtk_text_buffer_get_has_selection(buf); // Only since 2.10 } int gTextArea::selStart() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start,end; gtk_text_buffer_get_selection_bounds(buf,&start,&end); return gtk_text_iter_get_offset(&start); } int gTextArea::selEnd() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start,end; gtk_text_buffer_get_selection_bounds(buf,&start,&end); return gtk_text_iter_get_offset(&end); } char* gTextArea::selText() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start,end; gtk_text_buffer_get_selection_bounds(buf,&start,&end); return gtk_text_buffer_get_text(buf,&start,&end,true); } void gTextArea::setSelText(const char *vl) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start,end; if (!vl) vl=""; if (gtk_text_buffer_get_selection_bounds(buf,&start,&end)) gtk_text_buffer_delete(buf,&start,&end); gtk_text_buffer_insert(buf,&start,vl,-1); } void gTextArea::selDelete() { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start,end; if (gtk_text_buffer_get_selection_bounds(buf,&start,&end)) { gtk_text_iter_set_offset(&end,gtk_text_iter_get_offset(&start)); gtk_text_buffer_select_range(buf,&start,&end); } } void gTextArea::selSelect(int start,int length) { GtkTextBuffer *buf=gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter Start,End; gtk_text_buffer_get_end_iter(buf,&Start); if ( gtk_text_iter_get_offset(&Start)text_window)->bin_window; gControl::updateCursor(cursor); if (!win) return; if (cursor) gdk_window_set_cursor(win, cursor); else { cursor = gdk_cursor_new_for_display(gtk_widget_get_display(widget), GDK_XTERM); gdk_window_set_cursor(win, cursor); gdk_cursor_unref(cursor); } } void gTextArea::waitForLayout(int *tw, int *th) { GtkTextBuffer *buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(widget)); GtkTextIter start; GtkTextIter end; gint w, h; gtk_text_layout_set_screen_width(GTK_TEXT_VIEW(widget)->layout, width()); gtk_text_buffer_get_bounds (buf, &start, &end); gtk_text_layout_invalidate (GTK_TEXT_VIEW(widget)->layout, &start, &end); gtk_text_layout_validate(GTK_TEXT_VIEW(widget)->layout, 0x7FFFFFFF); gtk_text_layout_get_size(GTK_TEXT_VIEW(widget)->layout, &w, &h); *tw = w; *th = h; } int gTextArea::textWidth() { int w, h; waitForLayout(&w, &h); return w; } int gTextArea::textHeight() { int w, h; waitForLayout(&w, &h); return h; }