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