Typo: 'carrage' -> 'carriage'.
[synfig.git] / synfig-studio / trunk / src / gtkmm / canvasview.cpp
index 93381d4..e317406 100644 (file)
@@ -6,6 +6,7 @@
 **
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
+**     Copyright (c) 2007 Chris Moore
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -446,7 +447,7 @@ public:
        {
 //             assert(view->layer_tree);
 
-               if(!view->layer_tree) { DEBUGPOINT(); synfig::error("canvas_view.layer_tree not defined!?"); return LayerList(); }
+               if(!view->layer_tree) { DEBUGPOINT(); synfig::error("%s:%d canvas_view.layer_tree not defined!?", __FILE__, __LINE__); return LayerList(); }
                return view->layer_tree->get_selected_layers();
        }
 
@@ -455,7 +456,7 @@ public:
        {
 //             assert(view->layer_tree);
 
-               if(!view->layer_tree) { DEBUGPOINT(); synfig::error("canvas_view.layer_tree not defined!?"); return 0; }
+               if(!view->layer_tree) { DEBUGPOINT(); synfig::error("%s:%d canvas_view.layer_tree not defined!?", __FILE__, __LINE__); return 0; }
                return view->layer_tree->get_selected_layer();
        }
 
@@ -464,7 +465,7 @@ public:
        {
 //             assert(view->layer_tree);
 
-               if(!view->layer_tree) { DEBUGPOINT(); synfig::error("canvas_view.layer_tree not defined!?"); return; }
+               if(!view->layer_tree) { DEBUGPOINT(); synfig::error("%s:%d canvas_view.layer_tree not defined!?", __FILE__, __LINE__); return; }
                view->layer_tree->select_layers(layer_list);
                //view->get_smach().process_event(EVENT_REFRESH_DUCKS);
 
@@ -783,7 +784,7 @@ CanvasView::CanvasView(etl::loose_handle<Instance> instance,etl::handle<synfigap
        refresh_time_window();
 
        /*! \todo We shouldn't need to do this at construction --
-       **      This should be preformed at the first time the window
+       **      This should be performed at the first time the window
        **      becomes visible.
        */
        work_area->queue_render_preview();
@@ -796,6 +797,13 @@ CanvasView::CanvasView(etl::loose_handle<Instance> instance,etl::handle<synfigap
        int h=get_canvas()->rend_desc().get_h()+70;
        while(w>700 || h>600)
        {
+               // Minor hack:
+               //   zoom_out() =>
+               //         WorkArea::async_update_preview() =>
+               //           WorkArea::set_zoom(float) =>
+               //                 WorkArea::async_update_preview() =>
+               //                       desc.set_time(cur_time), where cur_time isn't initialized
+               work_area->set_time(0);
                work_area->zoom_out();
                w=round_to_int(get_canvas()->rend_desc().get_w()*work_area->get_zoom()+70);
                h=round_to_int(get_canvas()->rend_desc().get_h()*work_area->get_zoom()+70);
@@ -905,6 +913,10 @@ CanvasView::~CanvasView()
 
        hide();
 
+       // don't be calling on_dirty_preview once this object has been deleted;
+       // this was causing a crash before
+       canvas_interface()->signal_dirty_preview().clear();
+
        synfig::info("CanvasView:~CanvasView(): Destructor Finished");
 }
 
@@ -1209,8 +1221,11 @@ CanvasView::init_menus()
        action_group->add( Gtk::Action::create("options", _("Options")),
                sigc::mem_fun0(canvas_options,&studio::CanvasOptions::present)
        );
-       action_group->add( Gtk::Action::create("close", Gtk::StockID("gtk-close")),
-               sigc::hide_return(sigc::mem_fun(*this,&studio::CanvasView::close))
+       action_group->add( Gtk::Action::create("close", Gtk::StockID("gtk-close"), _("Close Window")),
+               sigc::hide_return(sigc::mem_fun(*this,&studio::CanvasView::close_view))
+       );
+       action_group->add( Gtk::Action::create("close-document", Gtk::StockID("gtk-close"), _("Close Document")),
+               sigc::hide_return(sigc::mem_fun(*this,&studio::CanvasView::close_instance))
        );
 
        //action_group->add( Gtk::Action::create("undo", Gtk::StockID("gtk-undo")),
@@ -1254,7 +1269,10 @@ CanvasView::init_menus()
                {
                        Glib::RefPtr<Gtk::RadioAction> action(Gtk::RadioAction::create(quality_group,strprintf("quality-%02d",i), strprintf("Set Quality to %d",i)));
                        if(i==10)
-                               action->property_value()=10;
+                       {
+                               action->set_active();
+                               work_area->set_quality(i);
+                       }
                        action_group->add( action,
                                sigc::bind(
                                        sigc::mem_fun(*work_area, &studio::WorkArea::set_quality),
@@ -1264,7 +1282,7 @@ CanvasView::init_menus()
                }
        }
 
-       action_group->add( Gtk::Action::create("play", Gtk::StockID("synfig-play")),
+       action_group->add( Gtk::Action::create("play", Gtk::Stock::MEDIA_PLAY),
                sigc::mem_fun(*this, &studio::CanvasView::play)
        );
 
@@ -1445,7 +1463,12 @@ CanvasView::init_menus()
                sigc::mem_fun(canvas_options,&studio::CanvasOptions::present)
        ));
        filemenu.items().push_back(Gtk::Menu_Helpers::SeparatorElem());
-       filemenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-close"),sigc::hide_return(sigc::mem_fun(*this,&studio::CanvasView::close))));
+       filemenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Close View"),
+               sigc::hide_return(sigc::mem_fun(*this,&studio::CanvasView::close_view))
+       ));
+       filemenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Close Document"),
+               sigc::hide_return(sigc::mem_fun(*this,&studio::CanvasView::close_document))
+       ));
 
        editmenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-undo"),Gtk::AccelKey('Z',Gdk::CONTROL_MASK),SLOT_EVENT(EVENT_UNDO)));
        editmenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-redo"),Gtk::AccelKey('R',Gdk::CONTROL_MASK),SLOT_EVENT(EVENT_REDO)));
@@ -1572,7 +1595,7 @@ CanvasView::init_menus()
                viewmenu.items().push_back(Gtk::Menu_Helpers::MenuElem(_("Preview Quality"),qualitymenu));
        }
 
-       viewmenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("synfig-play"),
+       viewmenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::Stock::MEDIA_PLAY,
                sigc::mem_fun(*this, &studio::CanvasView::play)));
        viewmenu.items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("Flipbook Dialog"),
                sigc::mem_fun(*preview_dialog, &studio::Dialog_Preview::present)));
@@ -1925,9 +1948,40 @@ CanvasView::refresh_rend_desc()
 
 
 bool
-CanvasView::close()
+CanvasView::close_view()
 {
-       get_instance()->safe_close();
+       if(get_instance()->get_visible_canvases()==1)
+               close_instance();
+       else
+               hide();
+       return false;
+}
+
+static bool _close_instance(etl::handle<Instance> instance)
+{
+       etl::handle<Instance> argh(instance);
+       instance->safe_close();
+       synfig::info("closed");
+       return false;
+}
+
+bool
+CanvasView::close_instance()
+{
+       if (get_work_area()->get_updating())
+       {
+               get_work_area()->stop_updating(true); // stop and mark as cancelled
+
+               // give the workarea chances to stop updating
+               Glib::signal_timeout().connect(
+                       sigc::mem_fun(*this, &CanvasView::close_instance),
+                       250);
+       }
+       else
+               Glib::signal_timeout().connect(
+                       sigc::bind(sigc::ptr_fun(_close_instance),
+                                          (etl::handle<Instance>)get_instance()),
+                       250);
        return false;
 }
 
@@ -1945,6 +1999,8 @@ CanvasView::update_title()
 {
        string title;
 
+       if(get_instance()->synfigapp::Instance::get_action_count())
+               title="*";
        title+=etl::basename(get_instance()->get_file_name())
                +" : ";
        if(get_canvas()->get_name().empty())
@@ -1952,9 +2008,6 @@ CanvasView::update_title()
        else
                title+='"'+get_canvas()->get_name()+'"';
 
-       if(get_instance()->synfigapp::Instance::get_action_count())
-               title+=_(" (Unsaved)");
-
        if(get_instance()->synfigapp::Instance::in_repository())
        {
                title+=" (CVS";
@@ -2143,6 +2196,8 @@ CanvasView::on_layer_user_click(int button, Gtk::TreeRow /*row*/, LayerTree::Col
                                parammenu.items().clear();
 
                                Gtk::Menu *newlayers(manage(new Gtk::Menu()));
+                               // do we need this?  the code is all #ifdef'ed out anyway
+                               // newlayers->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), newlayers));
                                build_new_layer_menu(*newlayers);
 
                                parammenu.items().push_back(Gtk::Menu_Helpers::MenuElem("New Layer",*newlayers));
@@ -2378,7 +2433,7 @@ CanvasView::on_id_changed()
 void
 CanvasView::on_mode_changed(synfigapp::CanvasInterface::Mode mode)
 {
-       // If the aninimate flag was set in mode...
+       // If the animate flag was set in mode...
        if(mode&synfigapp::MODE_ANIMATE)
        {
                Gtk::Image *icon;
@@ -2551,7 +2606,7 @@ CanvasView::rebuild_ducks_layer_(synfig::TransformStack& transform_stack, Canvas
                        // do the bounding box thing
                        bbox|=transform_stack.perform(layer->get_bounding_rect());
 
-                       // Grab the layer's list pf parameters
+                       // Grab the layer's list of parameters
                        Layer::ParamList paramlist(layer->get_param_list());
 
                        // Grab the layer vocabulary
@@ -2826,7 +2881,10 @@ CanvasView::play()
                        studio::App::iteration(false);
 
                if(get_cancel_status())
+               {
+                       is_playing_=false;
                        return;
+               }
        }
        is_playing_=false;
 
@@ -2934,6 +2992,7 @@ CanvasView::on_waypoint_clicked(synfigapp::ValueDesc value_desc,synfig::Waypoint
        case 2:
                {
                        Gtk::Menu* waypoint_menu(manage(new Gtk::Menu()));
+                       waypoint_menu->signal_hide().connect(sigc::bind(sigc::ptr_fun(&delete_widget), waypoint_menu));
 
                        waypoint_menu->items().push_back(Gtk::Menu_Helpers::StockMenuElem(Gtk::StockID("gtk-jump-to"),
                                sigc::bind(
@@ -3015,8 +3074,8 @@ CanvasView::on_drop_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& con
 {
        // We will make this true once we have a solid drop
        bool success(false);
-       //synfig::info("Droped data of type \"%s\"",selection_data.get_data_type());
-       //synfig::info("Droped data of target \"%s\"",gdk_atom_name(selection_data->target));
+       //synfig::info("Dropped data of type \"%s\"",selection_data.get_data_type());
+       //synfig::info("Dropped data of target \"%s\"",gdk_atom_name(selection_data->target));
        //synfig::info("selection=\"%s\"",gdk_atom_name(selection_data->selection));
 
        if ((selection_data_.get_length() >= 0) && (selection_data_.get_format() == 8))
@@ -3052,8 +3111,8 @@ CanvasView::on_drop_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& con
                {
                        synfig::String selection_data((gchar *)(selection_data_.get_data()));
 
-                       // For some reason, GTK hands us a list of URL's seperated
-                       // by not only Carrage-Returns, but also Line-Feeds.
+                       // For some reason, GTK hands us a list of URLs separated
+                       // by not only Carriage-Returns, but also Line-Feeds.
                        // Line-Feeds will mess us up. Remove all the line-feeds.
                        while(selection_data.find_first_of('\r')!=synfig::String::npos)
                                selection_data.erase(selection_data.begin()+selection_data.find_first_of('\r'));
@@ -3081,8 +3140,8 @@ CanvasView::on_drop_drag_data_received(const Glib::RefPtr<Gdk::DragContext>& con
                                // Strip the "file://" part from the filename
                                filename=synfig::String(filename.begin()+sizeof("file://")-1,filename.end());
 
-                               String ext;
-                               try{ext=(String(filename.begin()+filename.find_last_of('.')+1,filename.end()));}catch(...){continue;}
+                               String ext(filename_extension(filename));
+                               if (ext.size()) ext = ext.substr(1); // skip initial '.'
 
                                // If this is a SIF file, then we need to do things slightly differently
                                if(ext=="sketch")
@@ -3401,7 +3460,7 @@ CanvasView::on_audio_offset_notify()
        sound_dialog->set_offset(t);
        disp_audio->queue_draw();
 
-       synfig::info("CanvasView::on_audio_offset_notify(): offset time set to %s",t.get_string(get_canvas()->rend_desc().get_frame_rate()).c_str());
+       // synfig::info("CanvasView::on_audio_offset_notify(): offset time set to %s",t.get_string(get_canvas()->rend_desc().get_frame_rate()).c_str());
 }
 
 void
@@ -3499,30 +3558,14 @@ CanvasView::set_ext_widget(const synfig::String& x, Gtk::Widget* y)
                keyframe_tree=dynamic_cast<KeyframeTree*>(y);
 }
 
-static bool _close_instance(etl::handle<Instance> instance)
-{
-       etl::handle<Instance> argh(instance);
-       instance->safe_close();
-       synfig::info("closed");
-       return false;
-}
-
 bool
 CanvasView::on_delete_event(GdkEventAny* event)
 {
-       if(get_instance()->get_visible_canvases()==1)
-       {
-               // Schedule a close to occur in a few moments
-               Glib::signal_timeout().connect(
-                       sigc::bind(
-                               sigc::ptr_fun(_close_instance),
-                               (etl::handle<Instance>)get_instance()
-                       )
-                       ,250
-               );
-       }
-       if(event)
-               return Gtk::Window::on_delete_event(event);
+       close_view();
+
+       //! \todo This causes the window to be deleted straight away - but what if we prompt 'save?' and the user cancels?
+       //                Is there ever any need to pass on the delete event to the window here?
+       // if(event) return Gtk::Window::on_delete_event(event);
 
        return true;
 }