1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2015 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
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 Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "nel/misc/gtk_displayer.h"
27 //#include <gobject/gobject.h>
28 #include <gdk/gdkkeysyms.h>
31 // automatically add gtk library
32 #pragma comment(lib, "gtk-1.3.lib")
33 #pragma comment(lib, "gdk-1.3.lib")
34 #pragma comment(lib, "glib-1.3.lib")
35 #pragma comment(lib, "gthread-1.3.lib")
38 #include "nel/misc/app_context.h"
39 #include "nel/misc/path.h"
40 #include "nel/misc/command.h"
41 #include "nel/misc/thread.h"
55 static vector
<string
> CommandHistory
;
56 static uint32 CommandHistoryPos
= 0;
59 static GtkWidget
*RootWindow
= NULL
, *OutputText
= NULL
, *InputText
= NULL
;
60 static GtkWidget
*hrootbox
= NULL
, *scrolled_win2
= NULL
;
66 CGtkDisplayer (const char *displayerName
) : CWindowDisplayer(displayerName
)
69 createLabel ("@Clear|CLEAR");
71 INelContext::getInstance().setWindowedApplication(true);
74 CGtkDisplayer::~CGtkDisplayer ()
81 gint
ButtonClicked(GtkWidget
*Widget
, gpointer
*Data
)
83 CGtkDisplayer
*disp
= (CGtkDisplayer
*) Data
;
85 // find the button and execute the command
86 CSynchronized
<std::vector
<CGtkDisplayer::CLabelEntry
> >::CAccessor
access (&(disp
->_Labels
));
87 for (uint i
= 0; i
< access
.value().size(); i
++)
89 if (access
.value()[i
].Hwnd
== Widget
)
91 if(access
.value()[i
].Value
== "@Clear|CLEAR")
93 // special commands because the clear must be called by the display thread and not main thread
98 // the button was found, add the command in the command stack
99 CSynchronized
<std::vector
<std::string
> >::CAccessor
accessCommands (&disp
->_CommandsToExecute
);
101 nlassert (!access
.value()[i
].Value
.empty());
102 nlassert (access
.value()[i
].Value
[0] == '@');
104 string::size_type pos
= access
.value()[i
].Value
.find ("|");
105 if (pos
!= string::npos
)
107 str
= access
.value()[i
].Value
.substr(pos
+1);
111 str
= access
.value()[i
].Value
.substr(1);
114 accessCommands
.value().push_back(str
);
123 void CGtkDisplayer::updateLabels ()
126 CSynchronized
<std::vector
<CLabelEntry
> >::CAccessor
access (&_Labels
);
127 for (uint i
= 0; i
< access
.value().size(); i
++)
129 if (access
.value()[i
].NeedUpdate
&& !access
.value()[i
].Value
.empty())
133 if (access
.value()[i
].Value
[0] != '@')
134 n
= access
.value()[i
].Value
;
137 string::size_type pos
= access
.value()[i
].Value
.find ('|');
138 if (pos
!= string::npos
)
140 n
= access
.value()[i
].Value
.substr (1, pos
- 1);
144 n
= access
.value()[i
].Value
.substr (1);
148 if (access
.value()[i
].Hwnd
== NULL
)
150 // create a button for command and label for variables
151 if (access
.value()[i
].Value
[0] == '@')
153 access
.value()[i
].Hwnd
= gtk_button_new_with_label (n
.c_str());
154 nlassert (access
.value()[i
].Hwnd
!= NULL
);
155 gtk_signal_connect (GTK_OBJECT (access
.value()[i
].Hwnd
), "clicked", GTK_SIGNAL_FUNC (ButtonClicked
), (gpointer
) this);
156 GtkLabel
*label
= GTK_LABEL(gtk_bin_get_child(GTK_BIN(access
.value()[i
].Hwnd
)));
157 gtk_label_set_justify (label
, GTK_JUSTIFY_LEFT
);
158 gtk_label_set_line_wrap (label
, FALSE
);
159 gtk_widget_show (GTK_WIDGET (access
.value()[i
].Hwnd
));
160 gtk_box_pack_start (GTK_BOX (hrootbox
), GTK_WIDGET (access
.value()[i
].Hwnd
), TRUE
, TRUE
, 0);
164 access
.value()[i
].Hwnd
= gtk_label_new ("");
165 gtk_label_set_justify (GTK_LABEL (access
.value()[i
].Hwnd
), GTK_JUSTIFY_LEFT
);
166 gtk_label_set_line_wrap (GTK_LABEL (access
.value()[i
].Hwnd
), FALSE
);
167 gtk_widget_show (GTK_WIDGET (access
.value()[i
].Hwnd
));
168 gtk_box_pack_start (GTK_BOX (hrootbox
), GTK_WIDGET (access
.value()[i
].Hwnd
), TRUE
, TRUE
, 0);
172 if (access
.value()[i
].Value
[0] != '@')
173 gtk_label_set_text (GTK_LABEL (access
.value()[i
].Hwnd
), n
.c_str());
175 access
.value()[i
].NeedUpdate
= false;
181 // windows delete event => quit
182 gint
delete_event (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
190 gint
KeyIn(GtkWidget
*Widget
, GdkEventKey
*Event
, gpointer
*Data
)
192 switch (Event
->keyval
)
195 gtk_entry_set_text (GTK_ENTRY(Widget
), "");
198 if (CommandHistoryPos
> 0) {
200 gtk_entry_set_text (GTK_ENTRY(Widget
), CommandHistory
[CommandHistoryPos
].c_str());
204 if (CommandHistoryPos
+ 1 < CommandHistory
.size())
207 gtk_entry_set_text (GTK_ENTRY(Widget
), CommandHistory
[CommandHistoryPos
].c_str());
211 gtk_signal_emit_by_name(GTK_OBJECT(Widget
),"activate");
215 gtk_signal_emit_stop_by_name(GTK_OBJECT(Widget
),"key_press_event");
221 gtk_widget_grab_focus (InputText
);
224 gint
KeyOut(GtkWidget
*Widget
, GdkEventKey
*Event
, gpointer
*Data
)
227 gtk_signal_emit_stop_by_name(GTK_OBJECT(Widget
),"key_press_event");
232 /*gint ButtonClear(GtkWidget *Widget, GdkEventKey *Event, gpointer *Data)
234 CGtkDisplayer *disp = (CGtkDisplayer *) Data;
242 // the user typed command, execute it
243 gint
cbValidateCommand (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
245 string cmd
= gtk_entry_get_text (GTK_ENTRY(widget
));
246 CommandHistory
.push_back (cmd
);
247 // execute the command
250 ICommand::execute (cmd
, *Log
);
251 // clear the input text
252 gtk_entry_set_text (GTK_ENTRY(widget
), "");
253 CommandHistoryPos
= CommandHistory
.size();
258 void CGtkDisplayer::setTitleBar (const string
&titleBar
)
261 if (!titleBar
.empty())
266 wn
+= "Nel Service Console (compiled " __DATE__
" " __TIME__
" in " + nlMode
+ " mode)";
268 //nlassert (RootWindow != NULL);
269 gtk_window_set_title (GTK_WINDOW (RootWindow
), wn
.c_str());
272 void CGtkDisplayer::open (std::string titleBar
, bool iconified
, sint x
, sint y
, sint w
, sint h
, sint hs
, sint fs
, const std::string
&fn
, bool ww
, CLog
*log
)
283 gtk_init (NULL
, NULL
);
288 RootWindow
= gtk_window_new (GTK_WINDOW_TOPLEVEL
);
289 gtk_window_set_default_size (GTK_WINDOW (RootWindow
), w
, h
);
290 gtk_signal_connect (GTK_OBJECT (RootWindow
), "delete_event", GTK_SIGNAL_FUNC (delete_event
), NULL
);
293 GtkWidget
*vrootbox
= gtk_vbox_new (FALSE
, 0);
294 nlassert (vrootbox
!= NULL
);
295 gtk_container_add (GTK_CONTAINER (RootWindow
), vrootbox
);
297 // Horizontal box (for labels)
298 hrootbox
= gtk_hbox_new (FALSE
, 0);
299 nlassert (hrootbox
!= NULL
);
300 gtk_box_pack_start (GTK_BOX (vrootbox
), hrootbox
, FALSE
, FALSE
, 0);
303 GtkWidget *button = gtk_button_new_with_label ("Clear");
304 nlassert (button != NULL);
305 gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (ButtonClear), (gpointer) this);
306 gtk_box_pack_start (GTK_BOX (hrootbox), button, FALSE, FALSE, 0);
309 scrolled_win2
= gtk_scrolled_window_new (NULL
, NULL
);
310 nlassert (scrolled_win2
!= NULL
);
311 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win2
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_ALWAYS
);
312 gtk_widget_show (scrolled_win2
);
313 gtk_container_add (GTK_CONTAINER (vrootbox
), scrolled_win2
);
315 OutputText
= gtk_text_view_new();
316 nlassert (OutputText
!= NULL
);
318 PangoFontDescription
*fontDesc
= pango_font_description_from_string("Monospace 10");
319 gtk_widget_modify_font(OutputText
, fontDesc
);
320 pango_font_description_free(fontDesc
);
322 GtkTextBuffer
*textBuffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(OutputText
));
324 gtk_text_buffer_get_end_iter(textBuffer
, &endIter
);
325 gtk_text_buffer_create_mark(textBuffer
, "endmark", &endIter
, false);
326 gtk_signal_connect(GTK_OBJECT(OutputText
),"key_press_event",GTK_SIGNAL_FUNC(KeyOut
),NULL
);
327 gtk_text_view_set_editable (GTK_TEXT_VIEW(OutputText
), FALSE
);
328 gtk_container_add (GTK_CONTAINER (scrolled_win2
), OutputText
);
331 InputText
= gtk_entry_new ();
332 nlassert (InputText
!= NULL
);
333 gtk_signal_connect (GTK_OBJECT(InputText
), "activate", GTK_SIGNAL_FUNC(cbValidateCommand
), NULL
);
334 gtk_signal_connect(GTK_OBJECT(InputText
),"key_press_event",GTK_SIGNAL_FUNC(KeyIn
),NULL
);
335 gtk_box_pack_start (GTK_BOX (vrootbox
), InputText
, FALSE
, FALSE
, 0);
337 // gtk_widget_show (button);
338 gtk_widget_show (OutputText
);
339 gtk_widget_show (InputText
);
341 gtk_widget_show (hrootbox
);
342 gtk_widget_show (vrootbox
);
343 gtk_widget_show (RootWindow
);
345 setTitleBar (titleBar
);
350 void CGtkDisplayer::clear ()
352 GtkTextBuffer
*buffer
;
353 GtkTextIter start
, end
;
355 // who is taking care of the iterators?
356 buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(OutputText
));
357 gtk_text_buffer_get_bounds(buffer
, &start
, &end
);
358 gtk_text_buffer_delete(buffer
, &start
, &end
);
361 gint
updateInterf (gpointer data
)
363 CGtkDisplayer
*disp
= (CGtkDisplayer
*)data
;
369 disp
->updateLabels ();
372 // Display the bufferized string
374 GtkAdjustment
*Adj
= gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(scrolled_win2
));
375 bool Bottom
= (Adj
->value
>= Adj
->upper
- Adj
->page_size
- Adj
->step_increment
);
376 bool textChanged
= false;
378 GtkTextBuffer
*buffer
= gtk_text_view_get_buffer(GTK_TEXT_VIEW(OutputText
));
379 GtkTextIter end_iter
;
380 gtk_text_buffer_get_end_iter(buffer
, &end_iter
);
382 std::list
<std::pair
<uint32
, std::string
> >::iterator it
;
384 CSynchronized
<std::list
<std::pair
<uint32
, std::string
> > >::CAccessor
access (&disp
->_Buffer
);
386 for (it
= access
.value().begin(); it
!= access
.value().end(); it
++)
388 uint32 col
= (*it
).first
;
389 GtkTextTag
*tag
= NULL
;
393 color
.red
= (col
>> 8) & 0xFF00;
394 color
.green
= col
& 0xFF00;
395 color
.blue
= (col
<< 8) & 0xFF00;
396 tag
= gtk_text_buffer_create_tag(buffer
, NULL
, "foreground-gdk", &color
, "foreground-set", TRUE
, NULL
);
398 gtk_text_buffer_insert_with_tags(buffer
, &end_iter
, (*it
).second
.c_str(), -1, tag
, NULL
);
402 access
.value().clear ();
405 if (Bottom
&& textChanged
)
407 GtkTextMark
*mark
= gtk_text_buffer_get_mark(buffer
, "endmark");
408 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(OutputText
), mark
, 0.0, true, 0.0, 1.0);
414 void CGtkDisplayer::display_main ()
417 // Manage windows message
420 gtk_timeout_add (10, updateInterf
, this);
425 void CGtkDisplayer::getWindowPos (uint32
&x
, uint32
&y
, uint32
&w
, uint32
&h
)
437 // remove stupid VC6 warnings
438 void foo_gtk_displayer_cpp() {}