1 /* fsv - 3D File System Visualizer
2  *
3  * Copyright (C)2009-2011 Yury P. Fedorchenko <yuryfdr@users.sf.net>
4  */
5 
6 /* This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 
21 
22 #include "common.h"
23 #include "fsvwindow.h"
24 #include "ogl.h"
25 #include "viewport.h"
26 #include "color.h"
27 #include "dirtree.h"
28 #include "about.h"
29 #include "camera.h"
30 #include "colexp.h"
31 #include "fsv.h"
32 #include "options_dlg.h"
33 #include "property_dlg.h"
34 
35 #include <iostream>
36 
37 #include "xmaps/birdseye_view.xpm"
38 #include "xmaps/fsv-icon.xpm"
39 // will_be_removed;
gui_update()40 void gui_update(){
41 	while (gtk_events_pending( ) > 0)
42 		gtk_main_iteration( );
43 }
gui_cursor(GtkWidget * widget,int glyph)44 void gui_cursor( GtkWidget *widget, int glyph ){
45   if(glyph<0)glyph=0;
46   /*Gdk::Window::*///Glib::wrap(widget)->get_window()->set_cursor(Gdk::Cursor(Gdk::CursorType(glyph)));
47   //gdk_window_set_cursor( , cursor );
48 }
49 /* This checks if the widget associated with the given adjustment is
50  * currently busy redrawing/reconfiguring itself, or is in steady state
51  * (this is used when animating widgets to avoid changing the adjustment
52  * too often, otherwise the widget can't keep up and things slow down) */
53 boolean
gui_adjustment_widget_busy(GtkAdjustment * adj)54 gui_adjustment_widget_busy( GtkAdjustment *adj )
55 {
56 	static const double threshold = (1.0 / 18.0);
57 	double t_prev;
58 	double t_now;
59 	double *tp;
60 
61 	/* ---- HACK ALERT ----
62 	 * This doesn't actually check GTK+ internals-- I'm not sure which
63 	 * ones are relevant here. This just checks the amount of time that
64 	 * has passed since the last time the function was called with the
65 	 * same adjustment and returned FALSE, and if it's below a certain
66 	 * threshold, the object is considered "busy" (returning TRUE) */
67 
68 	t_now = xgettime( );
69 
70 	tp = (double*)g_object_get_data( G_OBJECT(adj), "t_prev" );
71 	if (tp == NULL) {
72 		tp = (double*)xmalloc(sizeof(double));
73 		*tp = t_now;
74 		g_object_set_data_full( G_OBJECT(adj), "t_prev", tp, _xfree );
75 		return FALSE;
76 	}
77 
78 	t_prev = *tp;
79 
80 	if ((t_now - t_prev) > threshold) {
81 		*tp = t_now;
82 		return FALSE;
83 	}
84 
85 	return TRUE;
86 }
87 
88 // old C functions
window_set_access(boolean enabled)89 void window_set_access( boolean enabled ){
90 }
window_set_color_mode(ColorMode mode)91 void window_set_color_mode( ColorMode mode ){
92   //g_print("%s\n",__FUNCTION__);
93   Glib::RefPtr<Gtk::RadioAction> ra;
94   if(mode==COLOR_BY_NODETYPE){
95   ra = Glib::RefPtr<Gtk::RadioAction>::cast_dynamic(FsvWindow::current->ag_unsetsitive->get_action("ColType"));
96   if(ra) ra->set_active(mode==COLOR_BY_NODETYPE);
97   }
98   if(mode==COLOR_BY_TIMESTAMP){
99   ra = Glib::RefPtr<Gtk::RadioAction>::cast_dynamic(FsvWindow::current->ag_unsetsitive->get_action("ColTime"));
100   if(ra) ra->set_active(mode==COLOR_BY_TIMESTAMP);
101   }
102   if(mode==COLOR_BY_WPATTERN){
103   ra = Glib::RefPtr<Gtk::RadioAction>::cast_dynamic(FsvWindow::current->ag_unsetsitive->get_action("ColWild"));
104   if(ra) ra->set_active(mode==COLOR_BY_WPATTERN);
105   }
106 }
window_birdseye_view_off(void)107 void window_birdseye_view_off( void ){
108   FsvWindow::current->birdeye->set_active(false);
109 }
window_statusbar(StatusBarID sb_id,const char * message)110 void window_statusbar( StatusBarID sb_id, const char *message ){
111   window_statusbar( sb_id, std::string(message) );
112 }
window_statusbar(StatusBarID sb_id,const std::string & message)113 void window_statusbar( StatusBarID sb_id, const std::string& message ){
114   if(sb_id == SB_RIGHT){
115   FsvWindow::current->rsbar.pop(sb_id);
116   FsvWindow::current->rsbar.push(message,sb_id);
117     return;
118   }
119   FsvWindow::current->sbar.pop(sb_id);
120   FsvWindow::current->sbar.push(message,sb_id);
121 }
122 // old C functions
context_menu(GNode * node,GdkEventButton * ev_button)123 void context_menu( GNode *node, GdkEventButton *ev_button ){
124   FsvWindow::current->popa_node = node;
125   Gtk::Menu::MenuList& items = FsvWindow::current->popa->items();
126   for(Gtk::Menu::MenuList::iterator it = items.begin();it!=items.end();++it){
127     it->hide();
128   }
129 	/* Check for the special case in which the menu has only one item */
130 	/*if (!NODE_IS_DIR(node) && (node == globals.current_node)) {
131 		items[4].show();//dialog_node_properties( node );
132 		//return;
133 	}*/
134 	if (NODE_IS_DIR(node)) {
135 		if (dirtree_entry_expanded( node ))
136 			items[1].show();
137 		else {
138 			items[2].show();
139 			if (DIR_NODE_DESC(node)->subtree.counts[NODE_DIRECTORY] > 0)
140 				items[3].show();
141 			}
142 	}
143 	if (node != globals.current_node)	items[4].show();
144 	items[0].show();
145 	items[5].show();
146   FsvWindow::current->popa->popup(ev_button->button,ev_button->time);
147 }
148 
149 //
on_change_root()150 void FsvWindow::on_change_root(){
151 	Glib::ustring root_name = node_absname( root_dnode );
152   Gtk::FileChooserDialog dialog(_("Change Root Directory"), Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER );
153   dialog.set_transient_for(*this);
154   dialog.set_filename(root_name);
155   dialog.set_create_folders(false);
156   dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
157   dialog.add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK);
158   if (dialog.run() == Gtk::RESPONSE_OK){
159     std::string filename = dialog.get_filename();
160     dialog.hide();
161     get_window()->set_cursor(Gdk::Cursor(Gdk::WATCH));
162 	  fsv_load( filename.c_str() );
163     get_window()->set_cursor(Gdk::Cursor(Gdk::LEFT_PTR));
164   }
165 }
166 
on_exit()167 void FsvWindow::on_exit(){
168   hide();
169 #ifdef HAVE_GL_GLC_H
170   glcDeleteGLObjects();
171   glcDeleteFont(textFont);
172   glcContext(ctx);
173   exit(0);
174 #endif
175 }
on_about()176 void FsvWindow::on_about(){
177   about( ABOUT_BEGIN );
178 }
on_fsv_mode(FsvMode mode)179 void FsvWindow::on_fsv_mode(FsvMode mode){
180 	if (globalsc.fsv_mode != mode)
181 		fsv_set_mode( mode );
182 }
on_birdseye_view()183 void FsvWindow::on_birdseye_view(){
184   camera_birdseye_view(birdeye->get_active() );
185 }
186 //
on_fullscreen()187 void FsvWindow::on_fullscreen(){
188   if(fullscr->get_active()){
189     sbar.hide();
190     rsbar.hide();
191     fullscreen();
192   }else{
193     sbar.show();
194     rsbar.show();
195     unfullscreen();
196   }
197 }
198 
on_collapse()199 void FsvWindow::on_collapse(){
200 	colexp( popa_node, COLEXP_COLLAPSE_RECURSIVE );
201 }
on_expand()202 void FsvWindow::on_expand(){
203 	colexp( popa_node, COLEXP_EXPAND );
204 }
on_expand_all()205 void FsvWindow::on_expand_all(){
206 	colexp( popa_node, COLEXP_EXPAND_RECURSIVE );
207 }
on_look_at()208 void FsvWindow::on_look_at(){
209 	camera_look_at( popa_node );
210 }
on_properties()211 void FsvWindow::on_properties(){
212   PropertyDialog dlg(popa_node);
213   dlg.run();
214 }
215 
on_open()216 void FsvWindow::on_open(){
217   file = Gio::File::create_for_path(node_absname(popa_node));
218   Glib::RefPtr< Gio::AppInfo > app = file->query_default_handler();
219   //std::vector< Glib::RefPtr< Gio::AppInfo > > vat = Gio::AppInfo::get_all_for_type(file->query_info()->get_content_type());
220   Gio::AppInfo::launch_default_for_uri(file->get_uri());
221 }
222 
on_color_type(ColorMode col)223 void FsvWindow::on_color_type(ColorMode col){
224 	color_set_mode( col );
225 }
on_color_setup()226 void FsvWindow::on_color_setup(){
227   OptionsDialog dlg;
228   dlg.run();
229 }
230 
on_cd_root()231 void FsvWindow::on_cd_root(){
232 	camera_look_at( root_dnode );
233 }
on_cd_back()234 void FsvWindow::on_cd_back(){
235 	camera_look_at_previous();
236 }
on_cd_up()237 void FsvWindow::on_cd_up(){
238 	if (NODE_IS_DIR(globals.current_node->parent))
239 		camera_look_at( globals.current_node->parent );
240 }
241 
242 FsvWindow* FsvWindow::current;
243 Gtk::StockID FsvWindow::BIRDEYE("bird-eye");
244 Gtk::StockItem FsvWindow::BirdEye(FsvWindow::BIRDEYE,_("Top View"));
245 
246 #ifdef HAVE_GL_GLC_H
247 GLint textFont=-1;
248 #endif
249 
~FsvWindow()250 FsvWindow::~FsvWindow(){
251 #ifdef HAVE_GL_GLC_H
252   glcDeleteGLObjects();
253   glcDeleteFont(textFont);
254   glcDeleteContext(ctx);
255 #endif
256 }
257 
258 Glib::RefPtr<Gdk::Pixbuf> FsvWindow::fsvicon;
259 Glib::RefPtr<Gdk::Pixbuf> FsvWindow::node_type_mini_icons[NUM_NODE_TYPES];
260 
261 
FsvWindow()262 FsvWindow::FsvWindow() : Gtk::Window(){
263   Glib::RefPtr<Gtk::IconFactory> icfa=Gtk::IconFactory::create();
264   icfa->add(BIRDEYE,Gtk::IconSet(Gdk::Pixbuf::create_from_xpm_data(birdseye_view_xpm)));
265   Gtk::Stock::add(BirdEye);
266   icfa->add_default();
267   fsvicon = Gdk::Pixbuf::create_from_xpm_data(fsv_icon_xpm);
268   set_icon(fsvicon);
269 
270 	for(int i = 1; i < NUM_NODE_TYPES; i++){
271 	  if(NODE_DIRECTORY == i){
272 	    node_type_mini_icons[NODE_DIRECTORY] = render_icon(Gtk::Stock::DIRECTORY,Gtk::IconSize(Gtk::ICON_SIZE_MENU));
273 	  }else if(NODE_REGFILE == i){
274 	    node_type_mini_icons[NODE_REGFILE] = render_icon(Gtk::Stock::FILE,Gtk::IconSize(Gtk::ICON_SIZE_MENU));
275 	  }else{
276 		  node_type_mini_icons[i] = Gdk::Pixbuf::create_from_xpm_data(node_type_mini_xpms[i]);
277 		}
278 	}
279   add(bx_main);
280   bx_main.set_homogeneous(false);
281   ag_unsetsitive = Gtk::ActionGroup::create("unsens");
282   ag_unsetsitive->add(Gtk::Action::create("Chroot",_("_Change Root")),
283                   sigc::mem_fun(*this,&FsvWindow::on_change_root) );
284 
285   Gtk::RadioAction::Group group_mode;
286   ag_unsetsitive->add(Gtk::RadioAction::create(group_mode,"MapV",_("_Map View")),
287                   sigc::bind(sigc::mem_fun(*this,&FsvWindow::on_fsv_mode),FSV_MAPV) );
288   ag_unsetsitive->add(Gtk::RadioAction::create(group_mode,"TreeV",_("_Tree View")),
289                   sigc::bind(sigc::mem_fun(*this,&FsvWindow::on_fsv_mode),FSV_TREEV) );
290   ag_unsetsitive->add(Gtk::RadioAction::create(group_mode,"DiskV",_("_Disc View")),
291                   sigc::bind(sigc::mem_fun(*this,&FsvWindow::on_fsv_mode),FSV_DISCV) );
292 
293   Gtk::RadioAction::Group group_color;
294 
295   ag_unsetsitive->add(Gtk::RadioAction::create(group_color,"ColType",_("By n_odetype")),
296                   sigc::bind(sigc::mem_fun(*this,&FsvWindow::on_color_type),COLOR_BY_NODETYPE) );
297   ag_unsetsitive->add(Gtk::RadioAction::create(group_color,"ColTime",_("By t_imestamp")),
298                   sigc::bind(sigc::mem_fun(*this,&FsvWindow::on_color_type),COLOR_BY_TIMESTAMP) );
299   ag_unsetsitive->add(Gtk::RadioAction::create(group_color,"ColWild",_("By _wildcard")),
300                   sigc::bind(sigc::mem_fun(*this,&FsvWindow::on_color_type),COLOR_BY_WPATTERN) );
301   birdeye = Gtk::ToggleAction::create("Beye",BIRDEYE);
302   ag_unsetsitive->add(birdeye,sigc::mem_fun(*this,&FsvWindow::on_birdseye_view));
303   //Gtk
304   ag_unsetsitive->add(Gtk::Action::create("CDRoot",Gtk::Stock::GOTO_FIRST),
305                       sigc::mem_fun(*this,&FsvWindow::on_cd_root));
306   ag_unsetsitive->add(Gtk::Action::create("CDBack",Gtk::Stock::GO_BACK),
307                       sigc::mem_fun(*this,&FsvWindow::on_cd_back));
308   ag_unsetsitive->add(Gtk::Action::create("CDUp",Gtk::Stock::GO_UP),
309                       sigc::mem_fun(*this,&FsvWindow::on_cd_up));
310 
311   ag_unsetsitive->add(Gtk::Action::create("Opennode",_("Open")),
312                       sigc::mem_fun(*this,&FsvWindow::on_open));
313   ag_unsetsitive->add(Gtk::Action::create("Collapse",_("Collapse")),
314                       sigc::mem_fun(*this,&FsvWindow::on_collapse));
315   ag_unsetsitive->add(Gtk::Action::create("Expand",_("Expand")),
316                       sigc::mem_fun(*this,&FsvWindow::on_expand));
317   ag_unsetsitive->add(Gtk::Action::create("Expandall",_("Expand all")),
318                       sigc::mem_fun(*this,&FsvWindow::on_expand_all));
319   ag_unsetsitive->add(Gtk::Action::create("Lookat",_("Look at")),
320                       sigc::mem_fun(*this,&FsvWindow::on_look_at));
321   ag_unsetsitive->add(Gtk::Action::create("Properties",_("Properties")),
322                       sigc::mem_fun(*this,&FsvWindow::on_properties));
323 
324   ag_allways = Gtk::ActionGroup::create("main");
325   ag_allways->add(Gtk::Action::create("File",_("_File")));
326   ag_allways->add(Gtk::Action::create("View",_("_View")));
327   fullscr = Gtk::ToggleAction::create("FullScreen",_("_Full Screen"));
328   ag_allways->add(fullscr,Gtk::AccelKey("F11"),
329                   sigc::mem_fun(*this,&FsvWindow::on_fullscreen));
330   ag_allways->add(Gtk::Action::create("Quit",Gtk::Stock::QUIT),
331                   sigc::mem_fun(*this,&FsvWindow::on_exit));
332   ag_allways->add(Gtk::Action::create("Help",_("_Help")));
333   ag_allways->add(Gtk::Action::create("About",Gtk::Stock::ABOUT),
334                   sigc::mem_fun(*this,&FsvWindow::on_about));
335   ag_allways->add(Gtk::Action::create("Pref",Gtk::Stock::PREFERENCES),
336                   sigc::mem_fun(*this,&FsvWindow::on_color_setup) );
337 
338   ui_man = Gtk::UIManager::create();
339   ui_man->insert_action_group(ag_unsetsitive);
340   ui_man->insert_action_group(ag_allways);
341   add_accel_group(ui_man->get_accel_group());
342 
343   Glib::ustring ui_info =
344         "<ui>"
345         "  <menubar name='MenuBar'>"
346         "    <menu action='File'>"
347         "      <menuitem action='Chroot'/>"
348         "      <separator/>"
349         "      <menuitem action='Quit'/>"
350         "    </menu>"
351         "    <menu action='View'>"
352         "      <menuitem action='FullScreen'/>"
353         "      <separator/>"
354         "      <menuitem action='MapV'/>"
355         "      <menuitem action='TreeV'/>"
356         "      <separator/>"
357         "      <menuitem action='Beye'/>"
358         "      <separator/>"
359         "      <menuitem action='ColType'/>"
360         "      <menuitem action='ColTime'/>"
361         "      <menuitem action='ColWild'/>"
362         "      <separator/>"
363         "      <menuitem action='Pref'/>"
364         "    </menu>"
365         "    <menu action='Help'>"
366         "      <menuitem action='About'/>"
367         "    </menu>"
368         "  </menubar>"
369         "  <toolbar  name='ToolBar'>"
370         "    <toolitem action='CDRoot'/>"
371         "    <toolitem action='CDBack'/>"
372         "    <toolitem action='CDUp'/>"
373         //"    <separator action='Sep1'/>"
374         "    <toolitem action='Beye'/>"
375         "  </toolbar>"
376         "  <popup name='Popa'>"
377         "      <menuitem action='Opennode'/>"
378 //        "       <separator action='Sep1'/>"
379         "      <menuitem action='Collapse'/>"
380         "      <menuitem action='Expand'/>"
381         "      <menuitem action='Expandall'/>"
382         "      <menuitem action='Lookat'/>"
383 //        "       <separator action='Sep1'/>"
384         "      <menuitem action='Properties'/>"
385         "  </popup>"
386         "</ui>";
387 
388   #ifdef GLIBMM_EXCEPTIONS_ENABLED
389   try
390   {
391     ui_man->add_ui_from_string(ui_info);
392   }
393   catch(const Glib::Error& ex)
394   {
395     std::cerr << "building menus failed: " <<  ex.what();
396   }
397   #else
398   std::auto_ptr<Glib::Error> error;
399   ui_man->add_ui_from_string(ui_info, error);
400   if(error.get())
401   {
402     std::cerr << "building menus failed: " <<  error->what();
403   }
404   #endif //GLIBMM_EXCEPTIONS_ENABLED
405 
406   Gtk::Widget* pMenuBar = ui_man->get_widget("/MenuBar") ;
407   bx_left.pack_start(*pMenuBar, Gtk::PACK_SHRINK);
408   //
409   bx_main.pack_start(pn_main,true,true);
410 
411   Gtk::Widget* pToolBar = ui_man->get_widget("/ToolBar") ;
412 
413   bx_left.pack_start(*pToolBar,false,false);
414 
415   popa = dynamic_cast<Gtk::Menu*>(ui_man->get_widget("/Popa"));
416 
417   bx_left.pack_start(pn_left);
418   pn_left.set_size_request(150);
419   pn_main.add1(bx_left);
420 
421   pn_left.add1(scr_tree);
422   scr_tree.add(tr_dirs);
423 
424   pn_left.add2(scr_list);
425   scr_list.add(tr_files);
426 
427 	pn_main.add2(tbl_right);
428 
429   {
430 
431 	GtkWidget *gl_area_w;
432 	int bitmask = 0;
433 
434 	gl_area_w = ogl_widget_new( );
435 	bitmask |= GDK_EXPOSURE_MASK;
436 	bitmask |= GDK_POINTER_MOTION_MASK;
437 	bitmask |= GDK_BUTTON_MOTION_MASK;
438 	bitmask |= GDK_BUTTON1_MOTION_MASK;
439 	bitmask |= GDK_BUTTON2_MOTION_MASK;
440 	bitmask |= GDK_BUTTON3_MOTION_MASK;
441 	bitmask |= GDK_BUTTON_PRESS_MASK;
442 	bitmask |= GDK_BUTTON_RELEASE_MASK;
443 	bitmask |= GDK_LEAVE_NOTIFY_MASK;
444 	gtk_widget_set_events( GTK_WIDGET(gl_area_w), bitmask );
445 	gtk_widget_set_size_request( GTK_WIDGET(gl_area_w), 600, 480);
446 	g_signal_connect( GTK_OBJECT(gl_area_w), "event", G_CALLBACK(viewport_cb), NULL );
447 	Gtk::Widget* w=Glib::wrap(gl_area_w);
448 	tbl_right.attach(*w,0,1,0,1);
449 	tbl_right.attach(x_scroll,0,1,1,2,Gtk::FILL|Gtk::EXPAND,Gtk::SHRINK);
450 	tbl_right.attach(y_scroll,1,2,0,1,Gtk::SHRINK,Gtk::FILL|Gtk::EXPAND);
451 
452   }
453 	camera_pass_scrollbar_widgets( GTK_WIDGET(x_scroll.gobj()), GTK_WIDGET(y_scroll.gobj()) );
454 
455 	tbl_right.attach(rsbar,0,2,2,3,Gtk::FILL|Gtk::EXPAND,Gtk::SHRINK);
456   bx_left.pack_end(sbar,Gtk::PACK_SHRINK);
457   sbar.set_has_resize_grip(false);
458 //  rsbar.set_size_request(150);
459 
460 #if defined HAVE_FTGL
461   font = new FTTextureFont(DEFAULT_FONT_FILE);
462   font->CharMap(ft_encoding_unicode);
463   font->FaceSize(24.);
464   font->Outset(10.);
465 #elif defined HAVE_GL_GLC_H
466   ctx = glcGenContext();
467   glcContext(ctx);
468   //glcAppendCatalog("/usr/lib/X11/fonts/Type1");
469 
470   glcNewFontFromFamily(textFont, "Monospace");
471   glcFontFace(textFont, "Normal");
472   glcFont(textFont);
473   glcStringType(GLC_UTF8_QSO);
474   //glcRenderStyle(GLC_LINE);
475   glcRenderStyle(GLC_TEXTURE);
476 #endif
477   show_all_children();
478 };
479 
get_file_icon(const GNode * node,int size)480 Glib::RefPtr<Gdk::Pixbuf> FsvWindow::get_file_icon(const GNode* node,int size){
481   Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(node_absname(node));
482   Glib::RefPtr<Gio::FileInfo> fi = file->query_info();
483   Gtk::IconInfo ico = Gtk::IconTheme::get_default()->lookup_icon(
484                       fi->get_icon(),
485                       size,Gtk::ICON_LOOKUP_USE_BUILTIN);
486   Glib::RefPtr<Gdk::Pixbuf> pix_em;
487   if(fi->is_symlink()){
488     Gtk::IconInfo ico = Gtk::IconTheme::get_default()->lookup_icon(
489                       "emblem-symbolic-link",
490                       size/4.,Gtk::ICON_LOOKUP_USE_BUILTIN);
491     if(ico){
492       pix_em = ico.load_icon();
493       //return pix_em;
494     }
495   }
496   if(ico){
497     Glib::RefPtr<Gdk::Pixbuf> pix = ico.load_icon()->copy();
498     if(pix){
499       if(pix_em){
500         int w_d = pix->get_width ();
501         int w_s = pix_em->get_width ();
502         Gdk::Rectangle rect(3*w_d/4,0,w_s,w_s);
503         rect.intersect(Gdk::Rectangle(0,0,w_d,w_d));
504         pix_em->composite(pix,rect.get_x(),rect.get_y(),rect.get_width(),rect.get_height(),0.,0.,1.,1.,Gdk::INTERP_NEAREST,255);
505       }
506       return pix;
507     }
508   }
509   return FsvWindow::node_type_mini_icons[NODE_DESC(node)->type];
510 }
511 
512 #include <GL/gl.h>
513 
514 
text_init(void)515 void text_init( void ){}
text_pre(void)516 void text_pre( void ){
517 	glDisable( GL_LIGHTING );
518 	glDisable( GL_POLYGON_OFFSET_FILL );
519 	glEnable( GL_ALPHA_TEST );
520 	glEnable( GL_BLEND );
521 }
text_post(void)522 void text_post( void ){
523 	glDisable( GL_BLEND );
524 	glDisable( GL_ALPHA_TEST );
525 	glEnable( GL_POLYGON_OFFSET_FILL );
526 	glEnable( GL_LIGHTING );
527 }
528 
529 
530 static int
get_char_dims(const char * text,const XYvec * max_dims,XYvec * cdims,double * scale,int reallen)531 get_char_dims(const char *text, const XYvec *max_dims, XYvec *cdims ,double *scale, int reallen){
532   int len=0;
533   if(g_utf8_validate(text,-1,NULL)){
534 	  len = g_utf8_strlen(text,-1);
535 	  FTBBox box =  FsvWindow::current->font->BBox(text);
536 	  cdims->x=box.Upper().X()-box.Lower().X();
537 	  cdims->y=box.Upper().Y()-box.Lower().Y();
538     if(cdims->x*max_dims->y/24. > max_dims->x){
539 	    *scale= max_dims->x *24./ cdims->x;
540 	    cdims->x=max_dims->x/ *scale *24.;
541 	  }else
542       *scale=max_dims->y;
543   }else{
544 	  g_print("Filename :%s invalid\n",text);
545   }
546   return (reallen==0)?1:len;
547 }
548 
549 
550 /* Draws a straight line of text centered at the given position,
551  * fitting within the dimensions specified */
552 void
text_draw_straight(const char * text,const XYZvec * text_pos,const XYvec * text_max_dims)553 text_draw_straight( const char *text, const XYZvec *text_pos, const XYvec *text_max_dims )
554 {
555 	XYvec cdims;
556 	XYvec c0;
557 	double scale=1.;
558 	int len = get_char_dims( text, text_max_dims, &cdims ,&scale,0);
559 	/* Corners of first character */
560 	c0.x = text_pos->x - 0.5 * cdims.x *scale/24.;
561 	c0.y = text_pos->y - 0.5 * cdims.y *scale/24.;
562 	//c1.x = c0.x + cdims.x;
563 	//c1.y = c0.y + cdims.y;
564 
565     glPushMatrix();
566     glTranslated(c0.x,c0.y,text_pos->z);
567     glScaled(scale/24.,text_max_dims->y/24.,1.);//text_max_dims->y);
568     FsvWindow::current->font->Render(text);
569     glPopMatrix();
570 }
571 
572 
573 /* Draws a straight line of text centered at the given position, rotated
574  * to be tangent to a circle around the origin, and fitting within the
575  * dimensions specified (which are also rotated) */
576 void
text_draw_straight_rotated(const char * text,const RTZvec * text_pos,const XYvec * text_max_dims)577 text_draw_straight_rotated( const char *text, const RTZvec *text_pos, const XYvec *text_max_dims )
578 {
579 	XYvec cdims;
580 	XYvec c0;
581 	XYvec hdelta, vdelta;
582 	double sin_theta, cos_theta,scale;
583 
584 	int len = get_char_dims( text, text_max_dims, &cdims ,&scale,0);
585 
586 	sin_theta = sin( RAD(text_pos->theta) );
587 	cos_theta = cos( RAD(text_pos->theta) );
588 
589 	/* Vector to move from one character to the next */
590 	hdelta.x = sin_theta * cdims.x*scale/24.;
591 	hdelta.y = - cos_theta * cdims.x*scale/24.;
592 	/* Vector to move from bottom of character to top */
593 	vdelta.x = cos_theta * cdims.y*scale/24.;
594 	vdelta.y = sin_theta * cdims.y*scale/24.;
595 
596 	/* Corners of first character */
597 	c0.x = cos_theta * text_pos->r - 0.5 * ((double)len * hdelta.x + vdelta.x);
598 	c0.y = sin_theta * text_pos->r - 0.5 * ((double)len * hdelta.y + vdelta.y);
599 
600    glPushMatrix();
601     glTranslated(c0.x,c0.y,text_pos->z);
602     glRotated(-90.+text_pos->theta,0.,0.,1.);
603     glScalef(scale/24.,text_max_dims->y/24.,text_max_dims->y/24.);
604     FsvWindow::current->font->Render(text);
605     glPopMatrix();
606 }
607 /* Draws a curved arc of text, occupying no more than the depth and arc
608  * width specified. text_pos indicates outer edge (not center) of text */
609 void
text_draw_curved(const char * text,const RTZvec * text_pos,const RTvec * text_max_dims)610 text_draw_curved( const char *text, const RTZvec *text_pos, const RTvec *text_max_dims )
611 {
612 	XYvec straight_dims, cdims;
613 	XYvec char_pos;
614 	double char_arc_width, theta;
615 	double sin_theta, cos_theta;
616 	double text_r,scale;
617 
618 	/* Convert curved dimensions to straight equivalent */
619 	straight_dims.x = (PI / 180.0) * text_pos->r * text_max_dims->theta;
620 	straight_dims.y = text_max_dims->r;
621 
622 	int len = get_char_dims( text, &straight_dims, &cdims ,&scale,1);
623 
624 	/* Radius of center of text line */
625 	text_r = text_pos->r - 0.5 * cdims.y*scale/24.;
626 
627 	/* Arc width occupied by each character */
628 	char_arc_width = (180.0 / PI) * cdims.x*scale/24. / text_r;
629 
630   theta = text_pos->theta * 0.5 * char_arc_width;
631   sin_theta = sin( RAD(theta) );
632   cos_theta = cos( RAD(theta) );
633 
634   char_pos.x = cos_theta * text_r - 0.5 * cdims.y*scale/24.;
635   char_pos.y = sin_theta * text_r + 0.5 * cdims.x*scale/24.;
636   glPushMatrix();
637   glTranslated(char_pos.x,char_pos.y,text_pos->z);
638   glRotated(-90.,0,0,1);
639   glTranslated(0,-straight_dims.y/3.,0);
640   glScaled(scale/24.,straight_dims.y/24.,straight_dims.y/24.);
641   FsvWindow::current->font->Render(text);
642   glPopMatrix();
643 }
644 
645 
646