add mask smooth boundary
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / cwindowtool.C
index 80122c529a5e392c1db085c2b8e1fa71a7ea5e93..1c715f9d248886404b57013a44a76d4af01d470e 100644 (file)
@@ -1499,18 +1499,25 @@ CWindowMaskOnTrack::~CWindowMaskOnTrack()
 
 int CWindowMaskOnTrack::handle_event()
 {
-       int k = get_number();
+       CWindowMaskItem *track_item = 0;
+       int k = get_number(), track_id = -1;
 //printf("selected %d = %s\n", k, k<0 ? "()" : track_items[k]->get_text());
-       CWindowMaskItem *track_item = k >= 0 ? (CWindowMaskItem *)track_items[k] : 0;
-       Track *track = track_item ? mwindow->edl->tracks->get_track_by_id(track_item->id) : 0;
-       int track_id = track_item && track && track->record ? track_item->id : -1;
+       if( k >= 0 ) {
+               track_item = (CWindowMaskItem *)track_items[k];
+               Track *track = track_item ? mwindow->edl->tracks->get_track_by_id(track_item->id) : 0;
+               if( track && track->record ) track_id = track->get_id();
+       }
+       else
+               track_id = mwindow->cwindow->mask_track_id;
        set_back_color(track_id >= 0 ?
                gui->get_resources()->text_background :
                gui->get_resources()->text_background_disarmed);
-       gui->mask_on_track->update(track_item ? track_item->get_text() : "");
+       if( mwindow->cwindow->mask_track_id != track_id )
+               gui->mask_on_track->update(track_item ? track_item->get_text() : "");
        mwindow->cwindow->mask_track_id = track_id;
        mwindow->edl->local_session->solo_track_id = -1;
        gui->mask_solo_track->update(0);
+       gui->update();
        gui->update_preview(1);
        return 1;
 }
@@ -1518,9 +1525,14 @@ int CWindowMaskOnTrack::handle_event()
 void CWindowMaskOnTrack::update_items()
 {
        track_items.remove_all_objects();
+       int high_color = gui->get_resources()->button_highlighted;
        for( Track *track=mwindow->edl->tracks->first; track; track=track->next ) {
                if( track->data_type != TRACK_VIDEO ) continue;
-               int color = track->record ? -1 : RED;
+               MaskAutos *mask_autos = (MaskAutos*)track->automation->autos[AUTOMATION_MASK];
+               int color = !track->record ? RED : mask_autos->first ?  high_color : -1;
+               MaskAuto *mask_auto = (MaskAuto*)mask_autos->default_auto;
+               for( int i=0; color<0 && i<mask_auto->masks.size(); ++i )
+                       if( mask_auto->masks[i]->points.size() > 0 ) color = high_color;
                track_items.append(new CWindowMaskItem(track->title, track->get_id(), color));
        }
        update_list(&track_items);
@@ -1573,6 +1585,7 @@ int CWindowMaskTrackTumbler::do_event(int dir)
        mwindow->cwindow->mask_track_id = track_item ? track_item->id : -1;
        mwindow->edl->local_session->solo_track_id = -1;
        gui->mask_solo_track->update(0);
+       gui->update();
        gui->update_preview(1);
        return 1;
 }
@@ -1978,6 +1991,27 @@ int CWindowMaskFocus::handle_event()
        return 1;
 }
 
+CWindowMaskHelp::CWindowMaskHelp(MWindow *mwindow, CWindowMaskGUI *gui, int x, int y)
+ : BC_CheckBox(x, y, 0, _("Help"))
+{
+       this->mwindow = mwindow;
+       this->gui = gui;
+       set_tooltip(_("Show help text"));
+}
+
+CWindowMaskHelp::~CWindowMaskHelp()
+{
+}
+
+int CWindowMaskHelp::handle_event()
+{
+       gui->helped = get_value();
+       gui->resize_window(gui->get_w(),
+               gui->helped ? gui->help_h : gui->help_y);
+       gui->update();
+       return 1;
+}
+
 CWindowMaskDrawMarkers::CWindowMaskDrawMarkers(MWindow *mwindow, CWindowMaskGUI *gui, int x, int y)
  : BC_CheckBox(x, y, gui->markers, _("Markers"))
 {
@@ -2264,6 +2298,51 @@ int CWindowMaskGangFader::handle_event()
        return 1;
 }
 
+CWindowMaskGangFocus::CWindowMaskGangFocus(MWindow *mwindow,
+               CWindowMaskGUI *gui, int x, int y)
+ : BC_Toggle(x, y, mwindow->theme->get_image_set("gangpatch_data"), 0)
+{
+        this->mwindow = mwindow;
+        this->gui = gui;
+        set_tooltip(_("Gang rotate/scale/translate"));
+}
+
+CWindowMaskGangFocus::~CWindowMaskGangFocus()
+{
+}
+
+int CWindowMaskGangFocus::handle_event()
+{
+       return 1;
+}
+
+
+CWindowMaskSmooth::CWindowMaskSmooth(MWindow *mwindow,
+               CWindowMaskGUI *gui, int x, int y)
+ : BC_GenericButton(x, y, _("Smooth"))
+{
+       this->mwindow = mwindow;
+       this->gui = gui;
+       set_tooltip(_("Smooth boundary"));
+}
+int CWindowMaskSmooth::handle_event()
+{
+       return gui->smooth_mask(0);
+}
+
+CWindowMaskGangSmooth::CWindowMaskGangSmooth(MWindow *mwindow,
+               CWindowMaskGUI *gui, int x, int y)
+ : BC_Button(x, y, mwindow->theme->get_image_set("gangpatch_data"))
+{
+       this->mwindow = mwindow;
+       this->gui = gui;
+       set_tooltip(_("Smooth All"));
+}
+int CWindowMaskGangSmooth::handle_event()
+{
+       return gui->smooth_mask(1);
+}
+
 CWindowMaskBeforePlugins::CWindowMaskBeforePlugins(CWindowMaskGUI *gui, int x, int y)
  : BC_CheckBox(x,
        y,
@@ -2390,7 +2469,7 @@ int CWindowMaskGangFeather::handle_event()
 
 CWindowMaskGUI::CWindowMaskGUI(MWindow *mwindow, CWindowTool *thread)
  : CWindowToolGUI(mwindow, thread,
-       _(PROGRAM_NAME ": Mask"), 420, 680)
+       _(PROGRAM_NAME ": Mask"), 430, 680)
 {
        this->mwindow = mwindow;
        this->thread = thread;
@@ -2521,11 +2600,14 @@ void CWindowMaskGUI::create_objects()
        focus_x = new CWindowCoord(this, x1, y, cx);
        focus_x->create_objects();
        add_subwindow(focus = new CWindowMaskFocus(mwindow, this, del_x, y));
+       add_subwindow(gang_focus = new CWindowMaskGangFocus(mwindow, this, clr_x, y));
        y += focus_x->get_h() + margin;
        add_subwindow(title = new BC_Title(x, y, "Y:"));
        float cy = mwindow->edl->session->output_h / 2.f;
        focus_y = new CWindowCoord(this, x1, y, cy);
        focus_y->create_objects();
+       add_subwindow(smooth = new CWindowMaskSmooth(mwindow, this, del_x, y));
+       add_subwindow(gang_smooth = new CWindowMaskGangSmooth(mwindow, this, clr_x, y));
        y += focus_x->get_h() + 2*margin;
        BC_Bar *bar;
        add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
@@ -2533,20 +2615,23 @@ void CWindowMaskGUI::create_objects()
        add_subwindow(this->apply_before_plugins = new CWindowMaskBeforePlugins(this, 10, y));
        y += this->apply_before_plugins->get_h();
        add_subwindow(this->disable_opengl_masking = new CWindowDisableOpenGLMasking(this, 10, y));
-       y += this->disable_opengl_masking->get_h() + margin;
-       add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x));
-       y += bar->get_h() + margin;
-
-       y += margin;
+       add_subwindow(help = new CWindowMaskHelp(mwindow, this, del_x, y));
+       y += this->disable_opengl_masking->get_h() + 2*margin;
+       help_y = y;
+       add_subwindow(new BC_Bar(x, y, get_w()-2*x));
+       y += bar->get_h() + 2*margin;
        add_subwindow(title = new BC_Title(x, y, _(
                "Shift+LMB: move an end point\n"
                "Ctrl+LMB: move a control point\n"
                "Alt+LMB: to drag translate the mask\n"
-               "Shift+Key Delete to delete the point\n"
-               "Wheel Up/Dn: rotate around pointer\n"
-               "Shift+Wheel Up/Dn: scale around pointer\n"
-               "Shift+MMB: Toggle focus center at pointer")));
+               "Shift+Key Delete: to delete the point\n"
+               "Shift+MMB: Set Pivot Point at pointer\n"
+               "Wheel: rotate around Pivot Point\n"
+               "Shift+Wheel: scale around Pivot Point\n"
+               "Ctrl+Wheel: rotate/scale around pointer")));
+       help_h = y + title->get_h() + 2*margin;
        update();
+       resize_window(get_w(), help_y);
        unlock_window();
 }
 
@@ -2712,6 +2797,59 @@ void CWindowMaskGUI::update_buttons(MaskAuto *keyframe, int k)
        }
 }
 
+int CWindowMaskGUI::smooth_mask(int gang)
+{
+       MaskAutos *autos;
+       MaskAuto *keyframe;
+       Track *track;
+       MaskPoint *point;
+       SubMask *mask;
+#ifdef USE_KEYFRAME_SPANNING
+       int create_it = 0;
+#else
+       int create_it = 1;
+#endif
+
+       mwindow->undo->update_undo_before(_("mask smooth"), this);
+
+// Get existing keyframe
+       get_keyframe(track, autos, keyframe,
+                       mask, point, create_it);
+       if( track ) {
+#ifdef USE_KEYFRAME_SPANNING
+               MaskAuto temp_keyframe(mwindow->edl, autos);
+               temp_keyframe.copy_data(keyframe);
+               keyframe = &temp_keyframe;
+#endif
+               int k = mwindow->edl->session->cwindow_mask;
+               int n = gang ? keyframe->masks.size() : k+1;
+               for( int j=gang? 0 : k; j<n; ++j ) {
+                       SubMask *sub_mask = keyframe->get_submask(j);
+                       ArrayList<MaskPoint*> &points = sub_mask->points;
+                       int psz = points.size();
+                       if( psz < 3 ) continue;
+                       for( int i=0; i<psz; ++i ) {
+                               int i0 = i-1, i1 = i+1;
+                               if( i0 < 0 ) i0 = psz-1;
+                               if( i1 >= psz ) i1 = 0;
+                               MaskPoint *p0 = points[i0];
+                               MaskPoint *p  = points[i];
+                               MaskPoint *p1 = points[i1];
+                               float dx = p1->x - p0->x, dy = p1->y - p0->y;
+                               p->control_x1 = -dx/4;  p->control_y1 = -dy/4;
+                               p->control_x2 =  dx/4;  p->control_y2 =  dy/4;
+                       }
+               }
+#ifdef USE_KEYFRAME_SPANNING
+               autos->update_parameter(keyframe);
+#endif
+               update_preview();
+       }
+
+       mwindow->undo->update_undo_after(_("mask smooth"), LOAD_AUTOMATION);
+       return 1;
+}
+
 CWindowRulerGUI::CWindowRulerGUI(MWindow *mwindow, CWindowTool *thread)
  : CWindowToolGUI(mwindow, thread, _(PROGRAM_NAME ": Ruler"), 320, 240)
 {