1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * GimpTextEditor
5  * Copyright (C) 2002-2003, 2008  Sven Neumann <sven@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <gegl.h>
24 #include <gtk/gtk.h>
25 
26 #include "libgimpwidgets/gimpwidgets.h"
27 
28 #include "widgets-types.h"
29 
30 #include "core/gimp.h"
31 #include "core/gimpdatafactory.h"
32 #include "core/gimpmarshal.h"
33 
34 #include "text/gimptext.h"
35 
36 #include "gimphelp-ids.h"
37 #include "gimpmenufactory.h"
38 #include "gimptextbuffer.h"
39 #include "gimptexteditor.h"
40 #include "gimptextstyleeditor.h"
41 #include "gimpuimanager.h"
42 
43 #include "gimp-intl.h"
44 
45 
46 enum
47 {
48   TEXT_CHANGED,
49   DIR_CHANGED,
50   LAST_SIGNAL
51 };
52 
53 
54 static void   gimp_text_editor_finalize     (GObject         *object);
55 
56 static void   gimp_text_editor_text_changed (GtkTextBuffer   *buffer,
57                                              GimpTextEditor  *editor);
58 static void   gimp_text_editor_font_toggled (GtkToggleButton *button,
59                                              GimpTextEditor  *editor);
60 
61 
62 G_DEFINE_TYPE (GimpTextEditor, gimp_text_editor, GIMP_TYPE_DIALOG)
63 
64 #define parent_class gimp_text_editor_parent_class
65 
66 static guint text_editor_signals[LAST_SIGNAL] = { 0 };
67 
68 
69 static void
gimp_text_editor_class_init(GimpTextEditorClass * klass)70 gimp_text_editor_class_init (GimpTextEditorClass *klass)
71 {
72   GObjectClass *object_class = G_OBJECT_CLASS (klass);
73 
74   object_class->finalize = gimp_text_editor_finalize;
75 
76   klass->text_changed    = NULL;
77   klass->dir_changed     = NULL;
78 
79   text_editor_signals[TEXT_CHANGED] =
80     g_signal_new ("text-changed",
81                   G_TYPE_FROM_CLASS (klass),
82                   G_SIGNAL_RUN_FIRST,
83                   G_STRUCT_OFFSET (GimpTextEditorClass, text_changed),
84                   NULL, NULL,
85                   gimp_marshal_VOID__VOID,
86                   G_TYPE_NONE, 0);
87 
88   text_editor_signals[DIR_CHANGED] =
89     g_signal_new ("dir-changed",
90                   G_TYPE_FROM_CLASS (klass),
91                   G_SIGNAL_RUN_FIRST,
92                   G_STRUCT_OFFSET (GimpTextEditorClass, dir_changed),
93                   NULL, NULL,
94                   gimp_marshal_VOID__VOID,
95                   G_TYPE_NONE, 0);
96 }
97 
98 static void
gimp_text_editor_init(GimpTextEditor * editor)99 gimp_text_editor_init (GimpTextEditor *editor)
100 {
101   editor->view        = NULL;
102   editor->file_dialog = NULL;
103   editor->ui_manager  = NULL;
104 
105   switch (gtk_widget_get_default_direction ())
106     {
107     case GTK_TEXT_DIR_NONE:
108     case GTK_TEXT_DIR_LTR:
109       editor->base_dir = GIMP_TEXT_DIRECTION_LTR;
110       break;
111     case GTK_TEXT_DIR_RTL:
112       editor->base_dir = GIMP_TEXT_DIRECTION_RTL;
113       break;
114     }
115 }
116 
117 static void
gimp_text_editor_finalize(GObject * object)118 gimp_text_editor_finalize (GObject *object)
119 {
120   GimpTextEditor *editor = GIMP_TEXT_EDITOR (object);
121 
122   g_clear_pointer (&editor->font_name, g_free);
123   g_clear_object (&editor->ui_manager);
124 
125   G_OBJECT_CLASS (parent_class)->finalize (object);
126 }
127 
128 
129 /*  public functions  */
130 
131 GtkWidget *
gimp_text_editor_new(const gchar * title,GtkWindow * parent,Gimp * gimp,GimpMenuFactory * menu_factory,GimpText * text,GimpTextBuffer * text_buffer,gdouble xres,gdouble yres)132 gimp_text_editor_new (const gchar     *title,
133                       GtkWindow       *parent,
134                       Gimp            *gimp,
135                       GimpMenuFactory *menu_factory,
136                       GimpText        *text,
137                       GimpTextBuffer  *text_buffer,
138                       gdouble          xres,
139                       gdouble          yres)
140 {
141   GimpTextEditor *editor;
142   GtkWidget      *content_area;
143   GtkWidget      *toolbar;
144   GtkWidget      *style_editor;
145   GtkWidget      *scrolled_window;
146 
147   g_return_val_if_fail (title != NULL, NULL);
148   g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
149   g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
150   g_return_val_if_fail (GIMP_IS_MENU_FACTORY (menu_factory), NULL);
151   g_return_val_if_fail (GIMP_IS_TEXT (text), NULL);
152   g_return_val_if_fail (GIMP_IS_TEXT_BUFFER (text_buffer), NULL);
153 
154   editor = g_object_new (GIMP_TYPE_TEXT_EDITOR,
155                          "title",         title,
156                          "role",          "gimp-text-editor",
157                          "transient-for", parent,
158                          "help-func",     gimp_standard_help_func,
159                          "help-id",       GIMP_HELP_TEXT_EDITOR_DIALOG,
160                          NULL);
161 
162   gtk_dialog_add_button (GTK_DIALOG (editor),
163                          _("_Close"), GTK_RESPONSE_CLOSE);
164 
165   g_signal_connect (editor, "response",
166                     G_CALLBACK (gtk_widget_destroy),
167                     NULL);
168 
169   g_signal_connect_object (text_buffer, "changed",
170                            G_CALLBACK (gimp_text_editor_text_changed),
171                            editor, 0);
172 
173   editor->ui_manager = gimp_menu_factory_manager_new (menu_factory,
174                                                       "<TextEditor>",
175                                                       editor, FALSE);
176 
177   content_area = gtk_dialog_get_content_area (GTK_DIALOG (editor));
178 
179   toolbar = gimp_ui_manager_get_widget (editor->ui_manager,
180                                         "/text-editor-toolbar");
181 
182   if (toolbar)
183     {
184       gtk_box_pack_start (GTK_BOX (content_area), toolbar, FALSE, FALSE, 0);
185       gtk_widget_show (toolbar);
186     }
187 
188   style_editor = gimp_text_style_editor_new (gimp, text, text_buffer,
189                                              gimp_data_factory_get_container (gimp->font_factory),
190                                              xres, yres);
191   gtk_box_pack_start (GTK_BOX (content_area), style_editor, FALSE, FALSE, 0);
192   gtk_widget_show (style_editor);
193 
194   scrolled_window = gtk_scrolled_window_new (NULL, NULL);
195   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
196                                   GTK_POLICY_AUTOMATIC,
197                                   GTK_POLICY_AUTOMATIC);
198   gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 2);
199   gtk_box_pack_start (GTK_BOX (content_area), scrolled_window, TRUE, TRUE, 0);
200   gtk_widget_show (scrolled_window);
201 
202   editor->view = gtk_text_view_new_with_buffer (GTK_TEXT_BUFFER (text_buffer));
203   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (editor->view),
204                                GTK_WRAP_WORD_CHAR);
205   gtk_container_add (GTK_CONTAINER (scrolled_window), editor->view);
206   gtk_widget_show (editor->view);
207 
208   switch (editor->base_dir)
209     {
210     case GIMP_TEXT_DIRECTION_LTR:
211     case GIMP_TEXT_DIRECTION_TTB_RTL:
212     case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
213     case GIMP_TEXT_DIRECTION_TTB_LTR:
214     case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
215       gtk_widget_set_direction (editor->view, GTK_TEXT_DIR_LTR);
216       break;
217     case GIMP_TEXT_DIRECTION_RTL:
218       gtk_widget_set_direction (editor->view, GTK_TEXT_DIR_RTL);
219       break;
220     }
221 
222   gtk_widget_set_size_request (editor->view, 200, 64);
223 
224   editor->font_toggle =
225     gtk_check_button_new_with_mnemonic (_("_Use selected font"));
226   gtk_box_pack_start (GTK_BOX (content_area), editor->font_toggle,
227                       FALSE, FALSE, 0);
228   gtk_widget_show (editor->font_toggle);
229 
230   g_signal_connect (editor->font_toggle, "toggled",
231                     G_CALLBACK (gimp_text_editor_font_toggled),
232                     editor);
233 
234   gtk_widget_grab_focus (editor->view);
235 
236   gimp_ui_manager_update (editor->ui_manager, editor);
237 
238   return GTK_WIDGET (editor);
239 }
240 
241 void
gimp_text_editor_set_text(GimpTextEditor * editor,const gchar * text,gint len)242 gimp_text_editor_set_text (GimpTextEditor *editor,
243                            const gchar    *text,
244                            gint            len)
245 {
246   GtkTextBuffer *buffer;
247 
248   g_return_if_fail (GIMP_IS_TEXT_EDITOR (editor));
249   g_return_if_fail (text != NULL || len == 0);
250 
251   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->view));
252 
253   if (text)
254     gtk_text_buffer_set_text (buffer, text, len);
255   else
256     gtk_text_buffer_set_text (buffer, "", 0);
257 }
258 
259 gchar *
gimp_text_editor_get_text(GimpTextEditor * editor)260 gimp_text_editor_get_text (GimpTextEditor *editor)
261 {
262   GtkTextBuffer *buffer;
263 
264   g_return_val_if_fail (GIMP_IS_TEXT_EDITOR (editor), NULL);
265 
266   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (editor->view));
267 
268   return gimp_text_buffer_get_text (GIMP_TEXT_BUFFER (buffer));
269 }
270 
271 void
gimp_text_editor_set_direction(GimpTextEditor * editor,GimpTextDirection base_dir)272 gimp_text_editor_set_direction (GimpTextEditor    *editor,
273                                 GimpTextDirection  base_dir)
274 {
275   g_return_if_fail (GIMP_IS_TEXT_EDITOR (editor));
276 
277   if (editor->base_dir == base_dir)
278     return;
279 
280   editor->base_dir = base_dir;
281 
282   if (editor->view)
283     {
284       switch (editor->base_dir)
285         {
286         case GIMP_TEXT_DIRECTION_LTR:
287         case GIMP_TEXT_DIRECTION_TTB_RTL:
288         case GIMP_TEXT_DIRECTION_TTB_RTL_UPRIGHT:
289         case GIMP_TEXT_DIRECTION_TTB_LTR:
290         case GIMP_TEXT_DIRECTION_TTB_LTR_UPRIGHT:
291           gtk_widget_set_direction (editor->view, GTK_TEXT_DIR_LTR);
292           break;
293         case GIMP_TEXT_DIRECTION_RTL:
294           gtk_widget_set_direction (editor->view, GTK_TEXT_DIR_RTL);
295           break;
296         }
297     }
298 
299   gimp_ui_manager_update (editor->ui_manager, editor);
300 
301   g_signal_emit (editor, text_editor_signals[DIR_CHANGED], 0);
302 }
303 
304 GimpTextDirection
gimp_text_editor_get_direction(GimpTextEditor * editor)305 gimp_text_editor_get_direction (GimpTextEditor *editor)
306 {
307   g_return_val_if_fail (GIMP_IS_TEXT_EDITOR (editor), GIMP_TEXT_DIRECTION_LTR);
308 
309   return editor->base_dir;
310 }
311 
312 void
gimp_text_editor_set_font_name(GimpTextEditor * editor,const gchar * font_name)313 gimp_text_editor_set_font_name (GimpTextEditor *editor,
314                                 const gchar    *font_name)
315 {
316   g_return_if_fail (GIMP_IS_TEXT_EDITOR (editor));
317 
318   if (editor->font_name)
319     g_free (editor->font_name);
320 
321   editor->font_name = g_strdup (font_name);
322 
323   if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (editor->font_toggle)))
324     {
325       PangoFontDescription *font_desc = NULL;
326 
327       if (font_name)
328         font_desc = pango_font_description_from_string (font_name);
329 
330       gtk_widget_modify_font (editor->view, font_desc);
331 
332       if (font_desc)
333         pango_font_description_free (font_desc);
334     }
335 }
336 
337 const gchar *
gimp_text_editor_get_font_name(GimpTextEditor * editor)338 gimp_text_editor_get_font_name (GimpTextEditor *editor)
339 {
340   g_return_val_if_fail (GIMP_IS_TEXT_EDITOR (editor), NULL);
341 
342   return editor->font_name;
343 }
344 
345 
346 /*  private functions  */
347 
348 static void
gimp_text_editor_text_changed(GtkTextBuffer * buffer,GimpTextEditor * editor)349 gimp_text_editor_text_changed (GtkTextBuffer  *buffer,
350                                GimpTextEditor *editor)
351 {
352   g_signal_emit (editor, text_editor_signals[TEXT_CHANGED], 0);
353 }
354 
355 static void
gimp_text_editor_font_toggled(GtkToggleButton * button,GimpTextEditor * editor)356 gimp_text_editor_font_toggled (GtkToggleButton *button,
357                                GimpTextEditor  *editor)
358 {
359   PangoFontDescription *font_desc = NULL;
360 
361   if (gtk_toggle_button_get_active (button) && editor->font_name)
362     font_desc = pango_font_description_from_string (editor->font_name);
363 
364   gtk_widget_modify_font (editor->view, font_desc);
365 
366   if (font_desc)
367     pango_font_description_free (font_desc);
368 }
369