From: Good Guy Date: Mon, 12 Nov 2018 20:37:03 +0000 (-0700) Subject: update ffmpeg to 4.1, add sketcher plugin, crikey tweaks, titler colorpicker, keyfram... X-Git-Tag: 2019-08~186 X-Git-Url: https://cinelerra-gg.org/git/?a=commitdiff_plain;h=83bfb86d01b353bab485d0ccc336e0572bcb63c6;p=goodguy%2Fcinelerra.git update ffmpeg to 4.1, add sketcher plugin, crikey tweaks, titler colorpicker, keyframe locks+tweaks --- diff --git a/cinelerra-5.1/cinelerra/colorpicker.C b/cinelerra-5.1/cinelerra/colorpicker.C index 1b40fcf0..097bcec8 100644 --- a/cinelerra-5.1/cinelerra/colorpicker.C +++ b/cinelerra-5.1/cinelerra/colorpicker.C @@ -43,8 +43,8 @@ ColorPicker::ColorPicker(int do_alpha, const char *title) this->title = title; this->do_alpha = do_alpha; this->do_okcancel = 0; - this->output = BLACK; - this->alpha = 255; + this->output = this->orig_color = BLACK; + this->alpha = this->orig_alpha = 255; } ColorPicker::~ColorPicker() @@ -63,6 +63,8 @@ void ColorPicker::start_window(int output, int alpha, int do_okcancel) } return; } + this->orig_color = output; + this->orig_alpha = alpha; this->output = output; this->alpha = alpha; this->do_okcancel = do_okcancel; diff --git a/cinelerra-5.1/cinelerra/colorpicker.h b/cinelerra-5.1/cinelerra/colorpicker.h index 0ae021ed..ed3f5a95 100644 --- a/cinelerra-5.1/cinelerra/colorpicker.h +++ b/cinelerra-5.1/cinelerra/colorpicker.h @@ -69,6 +69,7 @@ public: void update_gui(int output, int alpha); BC_Window* new_gui(); + int orig_color, orig_alpha; int output, alpha; int do_alpha, do_okcancel; const char *title; diff --git a/cinelerra-5.1/cinelerra/filexml.C b/cinelerra-5.1/cinelerra/filexml.C index 8914ff44..8b7315ca 100644 --- a/cinelerra-5.1/cinelerra/filexml.C +++ b/cinelerra-5.1/cinelerra/filexml.C @@ -46,6 +46,7 @@ XMLBuffer::XMLBuffer(long buf_size, long max_size, int del) lmt = bfr + bsz; isz = max_size; destroy = del; + share_lock = new Mutex("XMLBuffer::share_lock"); } XMLBuffer::XMLBuffer(const char *buf, long buf_size, int del) @@ -56,6 +57,7 @@ XMLBuffer::XMLBuffer(const char *buf, long buf_size, int del) lmt = inp = bfr+bsz; isz = bsz; destroy = del; + share_lock = new Mutex("XMLBuffer::share_lock"); } XMLBuffer::XMLBuffer(long buf_size, char *buf, int del) @@ -66,11 +68,13 @@ XMLBuffer::XMLBuffer(long buf_size, char *buf, int del) lmt = outp = bfr+bsz; isz = bsz; destroy = del; + share_lock = new Mutex("XMLBuffer::share_lock"); } XMLBuffer::~XMLBuffer() { if( destroy ) delete [] bfr; + delete share_lock; } int XMLBuffer::demand(long len) @@ -111,15 +115,13 @@ int XMLBuffer::read(char *bp, int len) void XMLBuffer::copy_from(XMLBuffer *xbuf) { - if( bsz != xbuf->bsz ) { delete [] bfr; bfr = 0; } - if( !bfr ) bfr = new unsigned char[bsz = xbuf->bsz]; - lmt = bfr + bsz; - long ilen = xbuf->otell(), olen = xbuf->itell(); - inp = pos(ilen); - outp = pos(olen); - if( ilen > 0 ) - memmove(bfr, xbuf->bfr, ilen); - destroy = xbuf->destroy; + xbuf->share_lock->lock("XMLBuffer::copy_from"); + share_lock->lock("XMLBuffer::copy_from"); + oseek(0); + write((const char*)xbuf->pos(0), xbuf->otell()); + iseek(xbuf->itell()); + xbuf->share_lock->unlock(); + share_lock->unlock(); } @@ -382,6 +384,7 @@ FileXML::FileXML(int coded) FileXML::~FileXML() { if( !shared ) delete buffer; + else buffer->share_lock->unlock(); delete [] output; } @@ -633,9 +636,10 @@ int FileXML::set_shared_input(XMLBuffer *xbuf) strcpy(this->filename, ""); delete buffer; buffer = xbuf; + xbuf->share_lock->lock("FileXML::set_shared_input"); xbuf->iseek(0); - set_coding(coded); shared = 1; + set_coding(coded); return 0; } @@ -644,9 +648,10 @@ int FileXML::set_shared_output(XMLBuffer *xbuf) strcpy(this->filename, ""); delete buffer; buffer = xbuf; + xbuf->share_lock->lock("FileXML::set_shared_output"); xbuf->oseek(0); - set_coding(coded); shared = 1; + set_coding(coded); return 0; } diff --git a/cinelerra-5.1/cinelerra/filexml.h b/cinelerra-5.1/cinelerra/filexml.h index 70950384..602a411e 100644 --- a/cinelerra-5.1/cinelerra/filexml.h +++ b/cinelerra-5.1/cinelerra/filexml.h @@ -27,6 +27,7 @@ #include #include "arraylist.h" +#include "mutex.h" #include "keyframe.inc" #include "filexml.inc" #include "sizes.h" @@ -38,9 +39,11 @@ class XMLBuffer long bsz, isz; unsigned char *inp, *outp, *bfr, *lmt; int destroy; + Mutex *share_lock; int demand(long len); friend class KeyFrame; + friend class FileXML; public: XMLBuffer(long buf_size=0x1000, long max_size=LONG_MAX, int del=1); XMLBuffer(long buf_size, char *buf, int del=0); // writing diff --git a/cinelerra-5.1/cinelerra/keyframe.C b/cinelerra-5.1/cinelerra/keyframe.C index faad855b..8d6a5755 100644 --- a/cinelerra-5.1/cinelerra/keyframe.C +++ b/cinelerra-5.1/cinelerra/keyframe.C @@ -37,6 +37,12 @@ KeyFrame::KeyFrame() xbuf = new XMLBuffer(); } +KeyFrame::KeyFrame(const char *buf, long len) + : Auto() +{ + xbuf = new XMLBuffer(buf, len, 0); +} + KeyFrame::KeyFrame(EDL *edl, KeyFrames *autos) : Auto(edl, (Autos*)autos) { diff --git a/cinelerra-5.1/cinelerra/keyframe.h b/cinelerra-5.1/cinelerra/keyframe.h index 89edf1f9..d766b915 100644 --- a/cinelerra-5.1/cinelerra/keyframe.h +++ b/cinelerra-5.1/cinelerra/keyframe.h @@ -37,6 +37,7 @@ class KeyFrame : public Auto KeyFrame &operator =(KeyFrame &k) { return k; } //illegal public: KeyFrame(); + KeyFrame(const char *buf, long len); KeyFrame(EDL *edl, KeyFrames *autos); virtual ~KeyFrame(); diff --git a/cinelerra-5.1/cinelerra/pluginclient.C b/cinelerra-5.1/cinelerra/pluginclient.C index 606f83d9..4e2c2984 100644 --- a/cinelerra-5.1/cinelerra/pluginclient.C +++ b/cinelerra-5.1/cinelerra/pluginclient.C @@ -43,13 +43,13 @@ #include "track.h" #include "transportque.inc" - +#include +#include +#include +#include +#include #include #include -#include - - - PluginClientThread::PluginClientThread(PluginClient *client) @@ -551,38 +551,38 @@ void PluginClient::load_defaults_xml() using_defaults = 1; //printf("PluginClient::load_defaults_xml %d %s\n", __LINE__, path); - KeyFrame temp_keyframe; - FILE *fp = fopen(path, "r"); - if( fp ) { - struct stat st; int fd = fileno(fp); - int64_t sz = !fstat(fd, &st) ? st.st_size : BCTEXTLEN; - char *data = temp_keyframe.get_data(sz+1); - int data_size = fread(data, 1, sz, fp); - if( data_size < 0 ) data_size = 0; - if( data_size > 0 ) { - data[data_size] = 0; - temp_keyframe.xbuf->oseek(data_size); + char *data = 0; + int64_t len = -1; + struct stat st; + int fd = open(path, O_RDONLY); + if( fd >= 0 && !fstat(fd, &st) ) { + int64_t sz = st.st_size; + data = new char[sz+1]; + len = read(fd, data, sz); + close(fd); + } + if( data && len >= 0 ) { + data[len] = 0; // Get window extents - int i = 0; - for( int state=0; i<(data_size-8) && state>=0; ++i ) { - if( !data[i] || data[i] == '<' ) break; - if( !isdigit(data[i]) ) continue; - if( !state ) { - window_x = atoi(data + i); - state = 1; - } - else { - window_y = atoi(data + i); - state = -1; - } - while( i=0; ++i ) { + if( !data[i] || data[i] == '<' ) break; + if( !isdigit(data[i]) ) continue; + if( !state ) { + window_x = atoi(data+i); + state = 1; + } + else { + window_y = atoi(data+i); + state = -1; } - temp_keyframe.xbuf->iseek(i); - read_data(&temp_keyframe); + while( i Main Menu (- is a checkbox) - 06/26/2018 update + 11/08/2018 update
@@ -1380,6 +1380,12 @@ Double click On fade/speed, synch video/audio ganged + +
+
+ Double MMB + On fade/speed, select keyframe position +
'U' @@ -1464,6 +1470,18 @@

+ + Patchbay + Shift/Move + Hold LMB + On Fade slider bar, sets gain to 100% or 0db + + +
+
+
+
+ Compositor
diff --git a/cinelerra-5.1/ffmpeg/plugin.opts b/cinelerra-5.1/ffmpeg/plugin.opts index dca6523b..27fcfaed 100644 --- a/cinelerra-5.1/ffmpeg/plugin.opts +++ b/cinelerra-5.1/ffmpeg/plugin.opts @@ -320,7 +320,6 @@ tlut2 ; new in 4.0 #acontrast Contrast=33 #afir -aiir #convolve #deconvolve drmeter @@ -334,3 +333,34 @@ normalize setrange #unpremultiply vfrdet +; new in 4.1 +acue +#adeclick +#adeclip +aderivative +afftdn +aintegral +amplify +chromahold +cue +deblock +fttdnoiz +#graphmonitor +greyedge +#highshelf +#lowshelf +lut1d +pal75bars +pal100bars +setparams +#sinc +tmix +vibrance +; broken in 4.1 +#acrossover +#aiir +#amultiply +#bm3d +#sr +#xstack +#agraphmonitor diff --git a/cinelerra-5.1/guicast/bcpopupmenu.C b/cinelerra-5.1/guicast/bcpopupmenu.C index 4c639fe2..2fb69d1c 100644 --- a/cinelerra-5.1/guicast/bcpopupmenu.C +++ b/cinelerra-5.1/guicast/bcpopupmenu.C @@ -53,11 +53,8 @@ BC_PopupMenu::BC_PopupMenu(int x, highlighted = popup_down = 0; menu_popup = 0; icon = 0; - if(margin >= 0) - this->margin = margin; - else - this->margin = BC_WindowBase::get_resources()->popupmenu_margin; - + this->margin = margin >= 0 ? margin : + BC_WindowBase::get_resources()->popupmenu_margin; this->use_title = use_title; strcpy(this->text, text); for(int i = 0; i < TOTAL_IMAGES; i++) @@ -80,6 +77,7 @@ BC_PopupMenu::BC_PopupMenu(int x, highlighted = popup_down = 0; menu_popup = 0; icon = 0; + this->margin = BC_WindowBase::get_resources()->popupmenu_margin; this->use_title = use_title; strcpy(this->text, text); for(int i = 0; i < TOTAL_IMAGES; i++) diff --git a/cinelerra-5.1/guicast/bctextbox.C b/cinelerra-5.1/guicast/bctextbox.C index a7c8f5f7..c404877c 100644 --- a/cinelerra-5.1/guicast/bctextbox.C +++ b/cinelerra-5.1/guicast/bctextbox.C @@ -2686,12 +2686,8 @@ int BC_TumbleTextBoxText::button_press_event() BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, - int64_t default_value, - int64_t min, - int64_t max, - int x, - int y, - int text_w) + int64_t default_value, int64_t min, int64_t max, + int x, int y, int text_w) { reset(); this->x = x; @@ -2707,12 +2703,8 @@ BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, } BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, - int default_value, - int min, - int max, - int x, - int y, - int text_w) + int default_value, int min, int max, + int x, int y, int text_w) { reset(); this->x = x; @@ -2728,12 +2720,8 @@ BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, } BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, - float default_value_f, - float min_f, - float max_f, - int x, - int y, - int text_w) + float default_value_f, float min_f, float max_f, + int x, int y, int text_w, int precision) { reset(); this->x = x; @@ -2742,9 +2730,9 @@ BC_TumbleTextBox::BC_TumbleTextBox(BC_WindowBase *parent_window, this->max_f = max_f; this->default_value_f = default_value_f; this->text_w = text_w; + this->precision = precision; this->parent_window = parent_window; use_float = 1; - precision = 4; increment = 1; } diff --git a/cinelerra-5.1/guicast/bctextbox.h b/cinelerra-5.1/guicast/bctextbox.h index ffc5c0e4..70c99003 100644 --- a/cinelerra-5.1/guicast/bctextbox.h +++ b/cinelerra-5.1/guicast/bctextbox.h @@ -403,26 +403,14 @@ class BC_TumbleTextBox { public: BC_TumbleTextBox(BC_WindowBase *parent_window, - int64_t default_value, - int64_t min, - int64_t max, - int x, - int y, - int text_w); + int64_t default_value, int64_t min, int64_t max, + int x, int y, int text_w); BC_TumbleTextBox(BC_WindowBase *parent_window, - int default_value, - int min, - int max, - int x, - int y, - int text_w); + int default_value, int min, int max, + int x, int y, int text_w); BC_TumbleTextBox(BC_WindowBase *parent_window, - float default_value, - float min, - float max, - int x, - int y, - int text_w); + float default_value, float min, float max, + int x, int y, int text_w, int precision=4); virtual ~BC_TumbleTextBox(); int create_objects(); diff --git a/cinelerra-5.1/guicast/bcwindowbase.h b/cinelerra-5.1/guicast/bcwindowbase.h index ca73b39e..84cb0896 100644 --- a/cinelerra-5.1/guicast/bcwindowbase.h +++ b/cinelerra-5.1/guicast/bcwindowbase.h @@ -310,6 +310,7 @@ public: int get_dragging(); wchar_t* get_wkeystring(int *length = 0); int get_keypress(); + int get_keysym() { return keysym; } #ifdef X_HAVE_UTF8_STRING char* get_keypress_utf8(); #endif diff --git a/cinelerra-5.1/guicast/test9.C b/cinelerra-5.1/guicast/test9.C new file mode 100644 index 00000000..a777d7f2 --- /dev/null +++ b/cinelerra-5.1/guicast/test9.C @@ -0,0 +1,117 @@ +#include "bcsignals.h" +#include "guicast.h" +#include "pys_icon_png.h" + +class TestList : public BC_ListBox +{ +public: + TestList(int x, int y, int w, int h, + ArrayList *items); + int handle_event(); + int selection_changed(); +}; + +TestList::TestList(int x, int y, int w, int h, + ArrayList *items) + : BC_ListBox(x, y, w, h, LISTBOX_TEXT, items, + 0, 0, 1, 0, 0, LISTBOX_SINGLE, ICON_LEFT, 0) +{ +} + +int TestList::handle_event() +{ + printf("handle_event\n"); + return 1; +} + +int TestList::selection_changed() +{ + BC_ListBoxItem *item = get_selection(0, 0); + printf("selection_changed %s\n", !item ? "" : item->get_text()); + return 1; +} + +class TestWindow : public BC_Window +{ +public: + TestWindow() : BC_Window("Test9", 0, 0, 320, 240) {}; + void create_objects(); + int keypress_event(); + BC_ListBox *list; + ArrayList items; +}; + +void TestWindow::create_objects() +{ + lock_window("AWindowRemovePluginGUI::create_objects"); + set_color(BLACK); + set_font(LARGEFONT); + int x = 10, y = 20; + draw_text(x, y, "Hello world"); + y += 25; + BC_Button *ok_button = new BC_OKButton(this); + add_subwindow(ok_button); + BC_Button *cancel_button = new BC_CancelButton(this); + add_subwindow(cancel_button); + BC_ListBoxItem *thing; + ArrayList *sublist; + items.append(thing = new BC_ListBoxItem("thing 1")); + VFrame *pys_icon = new VFramePng(pys_icon_png); + thing->set_icon_vframe(pys_icon); + int pw = pys_icon->get_w(), ph = pys_icon->get_h(); + BC_Pixmap *pys_picon = new BC_Pixmap(this, pw, ph); + pys_picon->draw_vframe(pys_icon, 0, 0, pw, pw, 0, 0); + thing->set_icon(pys_picon); + sublist = thing->new_sublist(1); + BC_ListBoxItem *fish, *cat, *hat; + sublist->append(fish = new BC_ListBoxItem("fish")); + ArrayList *fish_list = fish->new_sublist(1); + fish_list->append(new BC_ListBoxItem("green")); + fish_list->append(new BC_ListBoxItem("eggs")); + fish_list->append(new BC_ListBoxItem("ham")); + sublist->append(cat = new BC_ListBoxItem("cat")); + ArrayList *cat_list = cat->new_sublist(1); + cat_list->append(new BC_ListBoxItem("videos")); + sublist->append(hat = new BC_ListBoxItem("hat")); + ArrayList *hat_list = hat->new_sublist(1); + hat_list->append(new BC_ListBoxItem("bonnet")); + hat_list->append(new BC_ListBoxItem("cap")); + hat_list->append(new BC_ListBoxItem("sombrero")); + items.append(thing = new BC_ListBoxItem("thing 2")); + int lw = get_w()-x-10, lh = ok_button->get_y() - y - 5; + add_subwindow(list = new TestList(x, y, lw, lh, &items)); + show_window(); + unlock_window(); +} + +int TestWindow::keypress_event() +{ + switch( get_keypress() ) { + case 'v': + switch( list->get_format() ) { + case LISTBOX_TEXT: + list->update_format(LISTBOX_ICONS, 1); + break; + case LISTBOX_ICONS: + list->update_format(LISTBOX_ICONS_PACKED, 1); + break; + case LISTBOX_ICONS_PACKED: + list->update_format(LISTBOX_ICON_LIST, 1); + break; + case LISTBOX_ICON_LIST: + list->update_format(LISTBOX_TEXT, 1); + break; + } + break; + } + return 1; +} + +int main() +{ + new BC_Signals; + TestWindow window; + window.create_objects(); + window.run_window(); +} + diff --git a/cinelerra-5.1/plugin_defs b/cinelerra-5.1/plugin_defs index 9d94dd20..a5f8b45a 100644 --- a/cinelerra-5.1/plugin_defs +++ b/cinelerra-5.1/plugin_defs @@ -92,6 +92,7 @@ video := \ rumbler \ scale \ scaleratio \ + sketcher \ seltempavg \ shapewipe \ sharpen \ diff --git a/cinelerra-5.1/plugins/Makefile b/cinelerra-5.1/plugins/Makefile index 125de335..7833156e 100644 --- a/cinelerra-5.1/plugins/Makefile +++ b/cinelerra-5.1/plugins/Makefile @@ -117,6 +117,7 @@ DIRS = $(OPENCV_OBJS) \ rotate \ rumbler \ scale \ + sketcher \ shapewipe \ sharpen \ shiftinterlace \ diff --git a/cinelerra-5.1/plugins/crikey/crikey.C b/cinelerra-5.1/plugins/crikey/crikey.C index 2f22fed9..46d2402f 100644 --- a/cinelerra-5.1/plugins/crikey/crikey.C +++ b/cinelerra-5.1/plugins/crikey/crikey.C @@ -334,11 +334,12 @@ void CriKey::read_data(KeyFrame *keyframe) void CriKey::update_gui() { if( !thread ) return; - if( !load_configuration() ) return; thread->window->lock_window("CriKey::update_gui"); CriKeyWindow *window = (CriKeyWindow*)thread->window; - window->update_gui(); - window->flush(); + if( load_configuration() ) { + window->update_gui(); + window->flush(); + } thread->window->unlock_window(); } diff --git a/cinelerra-5.1/plugins/crikey/crikeywindow.C b/cinelerra-5.1/plugins/crikey/crikeywindow.C index eaaa0b5c..8d6d8644 100644 --- a/cinelerra-5.1/plugins/crikey/crikeywindow.C +++ b/cinelerra-5.1/plugins/crikey/crikeywindow.C @@ -129,6 +129,8 @@ CriKeyWindow::CriKeyWindow(CriKey *plugin) CriKeyWindow::~CriKeyWindow() { + delete point_x; + delete point_y; } void CriKeyWindow::create_objects() @@ -192,21 +194,23 @@ void CriKeyWindow::send_configure_change() pending_config = 0; plugin->send_configure_change(); } -int CriKeyWindow::check_configure_change(int ret) + +int CriKeyWindow::grab_event(XEvent *event) { + int ret = do_grab_event(event); if( pending_config && !grab_event_count() ) send_configure_change(); return ret; } -int CriKeyWindow::grab_event(XEvent *event) +int CriKeyWindow::do_grab_event(XEvent *event) { switch( event->type ) { case ButtonPress: break; case ButtonRelease: break; case MotionNotify: break; default: - return check_configure_change(0); + return 0; } MWindow *mwindow = plugin->server->mwindow; @@ -219,25 +223,25 @@ int CriKeyWindow::grab_event(XEvent *event) if( !dragging ) { if( cx < 0 || cx >= mwindow->theme->ccanvas_w || cy < 0 || cy >= mwindow->theme->ccanvas_h ) - return check_configure_change(0); + return 0; } switch( event->type ) { case ButtonPress: - if( dragging ) return check_configure_change(0); + if( dragging ) return 0; if( event->xbutton.button == WHEEL_UP ) return threshold->wheel_event(1); if( event->xbutton.button == WHEEL_DOWN ) return threshold->wheel_event(-1); dragging = event->xbutton.state & ShiftMask ? -1 : 1; break; case ButtonRelease: - if( !dragging ) return check_configure_change(0); + if( !dragging ) return 0; dragging = 0; return 1; case MotionNotify: - if( !dragging ) return check_configure_change(0); + if( !dragging ) return 0; break; default: - return check_configure_change(0); + return 0; } float cursor_x = cx, cursor_y = cy; @@ -288,6 +292,7 @@ int CriKeyWindow::grab_event(XEvent *event) if( hot_point >= 0 && sz > 0 ) { CriKeyPoint *pt = points[hot_point]; point_list->set_point(hot_point, PT_X, pt->x = output_x); + point_list->set_point(hot_point, PT_Y, pt->y = output_y); for( int i=0; ie = i==hot_point ? !pt->e : 0; @@ -332,10 +337,7 @@ int CriKeyWindow::grab_event(XEvent *event) } last_x = output_x; last_y = output_y; - if( !grab_event_count() ) - send_configure_change(); - else - pending_config = 1; + pending_config = 1; return 1; } diff --git a/cinelerra-5.1/plugins/crikey/crikeywindow.h b/cinelerra-5.1/plugins/crikey/crikeywindow.h index 7338d2dd..3e897f80 100644 --- a/cinelerra-5.1/plugins/crikey/crikeywindow.h +++ b/cinelerra-5.1/plugins/crikey/crikeywindow.h @@ -203,8 +203,8 @@ public: void update_gui(); void start_color_thread(); int grab_event(XEvent *event); + int do_grab_event(XEvent *event); void done_event(int result); - int check_configure_change(int ret); void send_configure_change(); CriKey *plugin; diff --git a/cinelerra-5.1/plugins/sketcher/Makefile b/cinelerra-5.1/plugins/sketcher/Makefile new file mode 100644 index 00000000..a53e62f1 --- /dev/null +++ b/cinelerra-5.1/plugins/sketcher/Makefile @@ -0,0 +1,13 @@ +include ../../plugin_defs + +OBJS := \ + $(OBJDIR)/sketcher.o \ + $(OBJDIR)/sketcherwindow.o + +PLUGIN = sketcher + +include ../../plugin_config + +$(OBJDIR)/sketcher.o: sketcher.C +$(OBJDIR)/sketcherwindow.o: sketcherwindow.C + diff --git a/cinelerra-5.1/plugins/sketcher/sketcher.C b/cinelerra-5.1/plugins/sketcher/sketcher.C new file mode 100644 index 00000000..b9d729c9 --- /dev/null +++ b/cinelerra-5.1/plugins/sketcher/sketcher.C @@ -0,0 +1,652 @@ +/* + * CINELERRA + * Copyright (C) 1997-2015 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include + +#include "arraylist.h" +#include "bccmodels.h" +#include "bccolors.h" +#include "clip.h" +#include "edlsession.h" +#include "filexml.h" +#include "sketcher.h" +#include "sketcherwindow.h" +#include "language.h" +#include "vframe.h" + +void SketcherPoint::init(int id, int x, int y) +{ + this->id = id; + this->x = x; this->y = y; +} +SketcherPoint::SketcherPoint(int id) +{ + init(id, 0, 0); +} +SketcherPoint::SketcherPoint(int id, int x, int y) +{ + init(id, x, y); +} +SketcherPoint::~SketcherPoint() +{ +} +SketcherPoint::SketcherPoint(SketcherPoint &pt) +{ + copy_from(pt); +} +int SketcherPoint::equivalent(SketcherPoint &that) +{ + return this->id == that.id && + this->x == that.x && + this->y == that.y ? 1 : 0; +} +void SketcherPoint::copy_from(SketcherPoint &that) +{ + this->id = that.id; + this->x = that.x; this->y = that.y; +} +void SketcherPoint::save_data(FileXML &output) +{ + char point[BCSTRLEN]; + sprintf(point,"/POINT_%d",id); + output.tag.set_title(point+1); + output.tag.set_property("X", x); + output.tag.set_property("Y", y); + output.append_tag(); + output.tag.set_title(point+0); + output.append_tag(); + output.append_newline(); +} +void SketcherPoint::read_data(FileXML &input) +{ + id = atoi(input.tag.get_title() + 6); + x = input.tag.get_property("X", 0.f); + y = input.tag.get_property("Y", 0.f); +} + +void SketcherCurve::init(int id, int ty, int radius, int pen, int color) +{ + this->id = id; + this->ty = ty; + this->radius = radius; + this->pen = pen; + this->color = color; +} +SketcherCurve::SketcherCurve(int id) +{ + init(id, 0, 1, 0, BLACK); +} +SketcherCurve::SketcherCurve(int id, int ty, int radius,int pen, int color) +{ + init(id, ty, radius, pen, color); +} +SketcherCurve::~SketcherCurve() +{ +} +SketcherCurve::SketcherCurve(SketcherCurve &cv) +{ + copy_from(cv); +} +int SketcherCurve::equivalent(SketcherCurve &that) +{ + if( this->id != that.id ) return 0; + if( this->ty != that.ty ) return 0; + if( this->radius != that.radius ) return 0; + if( this->pen != that.pen ) return 0; + if( this->color != that.color ) return 0; + int n = this->points.size(); + if( n != that.points.size() ) return 0; + for( int i=0; iequivalent(*that.points[i]) ) return 0; + } + return 1; +} +void SketcherCurve::copy_from(SketcherCurve &that) +{ + this->id = that.id; + this->ty = that.ty; + this->radius = that.radius; + this->pen = that.pen; + this->color = that.color; + int m = points.size(), n = that.points.size(); + while( m > n ) points.remove_object_number(--m); + while( m < n ) { points.append(new SketcherPoint()); ++m; } + for( int i=0; icopy_from(*that.points[i]); +} +void SketcherCurve::save_data(FileXML &output) +{ + this->ty = ty; + this->pen = pen; this->color = color; + char curve[BCSTRLEN]; + sprintf(curve,"/CURVE_%d",id); + output.tag.set_title(curve+1); + output.tag.set_property("TYPE", ty); + output.tag.set_property("RADIUS", radius); + output.tag.set_property("PEN", pen); + output.tag.set_property("COLOR", color); + output.append_tag(); + output.append_newline(); + for( int i=0,n=points.size(); isave_data(output); + output.tag.set_title(curve+0); + output.append_tag(); + output.append_newline(); +} +void SketcherCurve::read_data(FileXML &input) +{ + id = atoi(input.tag.get_title() + 6); + ty = input.tag.get_property("TYPE", 0); + radius = input.tag.get_property("RADIUS", 1.); + pen = input.tag.get_property("PEN", 0); + color = input.tag.get_property("COLOR", BLACK); +} + +int Sketcher::new_curve(int ty, int radius, int pen, int color) +{ + SketcherCurves &curves = config.curves; + int k = curves.size(), id = 1; + for( int i=k; --i>=0; ) { + int n = config.curves[i]->id; + if( n >= id ) id = n + 1; + } + SketcherCurve *cv = new SketcherCurve(id, ty, radius, pen, color); + curves.append(cv); + config.cv_selected = k; + return k; +} + +int Sketcher::new_curve() +{ + return new_curve(0, 1, 0, BLACK); +} + +int Sketcher::new_point(SketcherCurve *cv, int x, int y) +{ + int k = cv->points.size(), id = 1; + for( int i=k; --i>=0; ) { + int n = cv->points[i]->id; + if( n >= id ) id = n + 1; + } + SketcherPoint *pt = new SketcherPoint(id, x, y); + cv->points.append(pt); + return k; +} + +int Sketcher::new_point() +{ + int ci = config.cv_selected; + if( ci < 0 || ci >= config.curves.size() ) + return -1; + SketcherCurve *cv = config.curves[ci]; + EDLSession *session = get_edlsession(); + int x = !session ? 0.f : session->output_w / 2.f; + int y = !session ? 0.f : session->output_h / 2.f; + return new_point(cv, x, y); +} + +REGISTER_PLUGIN(Sketcher) + +SketcherConfig::SketcherConfig() +{ + drag = 1; + cv_selected = 0; + pt_selected = 0; +} +SketcherConfig::~SketcherConfig() +{ +} + +int SketcherConfig::equivalent(SketcherConfig &that) +{ + if( this->drag != that.drag ) return 0; + if( this->cv_selected != that.cv_selected ) return 0; + if( this->pt_selected != that.pt_selected ) return 0; + if( this->curves.size() != that.curves.size() ) return 0; + for( int i=0, n=curves.size(); iequivalent(*that.curves[i]) ) return 0; + } + return 1; +} + +void SketcherConfig::copy_from(SketcherConfig &that) +{ + this->drag = that.drag; + this->cv_selected = that.cv_selected; + this->pt_selected = that.pt_selected; + int m = curves.size(), n = that.curves.size(); + while( m > n ) curves.remove_object_number(--m); + while( m < n ) { curves.append(new SketcherCurve()); ++m; } + for( int i=0; icopy_from(*that.curves[i]); +} + +void SketcherConfig::interpolate(SketcherConfig &prev, SketcherConfig &next, + long prev_frame, long next_frame, long current_frame) +{ + this->cv_selected = prev.cv_selected; + this->pt_selected = prev.pt_selected; + this->drag = prev.drag; + + double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame); + double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame); + + curves.remove_all_objects(); + int prev_cv_sz = prev.curves.size(); + int next_cv_sz = next.curves.size(); + for( int i=0; i= 0 && pcv->id != (ncv=next.curves[k])->id ); + if( k >= 0 ) { + cv->id = pcv->id; + cv->ty = pcv->ty; + cv->radius = pcv->radius; + cv->pen = pcv->pen; + cv->color = pcv->color; + int prev_pt_sz = pcv->points.size(), next_pt_sz = ncv->points.size(); + for( int j=0; jpoints[j], *nt = 0; + k = next_pt_sz; // associated by id in next + while( --k >= 0 && pt.id != (nt=ncv->points[k])->id ); + int x = pt.x, y = pt.y; + if( k >= 0 ) { + x = x * prev_scale + nt->x * next_scale; + y = y * prev_scale + nt->y * next_scale; + } + cv->points.append(new SketcherPoint(pt.id, x, y)); + } + } + else + cv->copy_from(*pcv); + } +} + +void SketcherConfig::limits() +{ +} + + +Sketcher::Sketcher(PluginServer *server) + : PluginVClient(server) +{ +} + +Sketcher::~Sketcher() +{ +} + +const char* Sketcher::plugin_title() { return N_("Sketcher"); } +int Sketcher::is_realtime() { return 1; } + +NEW_WINDOW_MACRO(Sketcher, SketcherWindow); +LOAD_CONFIGURATION_MACRO(Sketcher, SketcherConfig) + +void Sketcher::save_data(KeyFrame *keyframe) +{ + FileXML output; +// cause data to be stored directly in text + output.set_shared_output(keyframe->xbuf); + + output.tag.set_title("SKETCHER"); + output.tag.set_property("DRAG", config.drag); + output.tag.set_property("CURVE_SELECTED", config.cv_selected); + output.tag.set_property("POINT_SELECTED", config.pt_selected); + output.append_tag(); + output.append_newline(); + for( int i=0,n=config.curves.size(); isave_data(output); + } + output.tag.set_title("/SKETCHER"); + output.append_tag(); + output.append_newline(); + output.terminate_string(); +} + +void Sketcher::read_data(KeyFrame *keyframe) +{ + FileXML input; + input.set_shared_input(keyframe->xbuf); + config.curves.remove_all_objects(); + int result = 0; + SketcherCurve *cv = 0; + + while( !(result=input.read_tag()) ) { + if( input.tag.title_is("SKETCHER") ) { + config.drag = input.tag.get_property("DRAG", config.drag); + config.cv_selected = input.tag.get_property("CV_SELECTED", 0); + config.pt_selected = input.tag.get_property("PT_SELECTED", 0); + } + else if( !strncmp(input.tag.get_title(),"CURVE_",6) ) { + cv = new SketcherCurve(); + cv->read_data(input); + config.curves.append(cv); + } + else if( !strncmp(input.tag.get_title(),"/CURVE_",7) ) + cv = 0; + else if( !strncmp(input.tag.get_title(),"POINT_",6) ) { + if( cv ) { + SketcherPoint *pt = new SketcherPoint(); + pt->read_data(input); + cv->points.append(pt); + } + else + printf("Sketcher::read_data: no curve for point\n"); + } + } + + if( !config.curves.size() ) { + new_curve(0, 1, 0, BLACK); + } + config.limits(); +} + +void Sketcher::update_gui() +{ + if( !thread ) return; + thread->window->lock_window("Sketcher::update_gui"); + if( load_configuration() ) { + SketcherWindow *window = (SketcherWindow*)thread->window; + window->update_gui(); + window->flush(); + } + thread->window->unlock_window(); +} + +void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color, int d) +{ + int r = d/2+1, x = pt->x, y = pt->y; + vfrm->draw_smooth(x-r,y+0, x-r, y-r, x+0,y-r); + vfrm->draw_smooth(x+0,y-r, x+r, y-r, x+r,y+0); + vfrm->draw_smooth(x+r,y+0, x+r, y+r, x+0,y+r); + vfrm->draw_smooth(x+0,y+r, x-r, y+r, x-r,y+0); + vfrm->set_pixel_color(color); + vfrm->draw_x(pt->x, pt->y, d); +} +void Sketcher::draw_point(VFrame *vfrm, SketcherPoint *pt, int color) +{ + draw_point(vfrm, pt, color, bmax(w,h)/200 + 2); +} + + +int SketcherPenSquare::draw_pixel(int x, int y) +{ + vfrm->draw_line(x-n, y, x+n, y); + for( int i=-n; idraw_line(x-n, y+i, x+n, y+i); + return 0; +} +int SketcherPenPlus::draw_pixel(int x, int y) +{ + if( n > 1 ) { + vfrm->draw_line(x-n, y, x+n, y); + vfrm->draw_line(x, y-n, x, y+n); + } + else + vfrm->draw_pixel(x, y); + return 0; +} +int SketcherPenSlant::draw_pixel(int x, int y) +{ + vfrm->draw_line(x-n, y+n, x+n, y-n); + vfrm->draw_line(x-n+1, y+n, x+n+1, y-n); + vfrm->draw_line(x-n, y+n+1, x+n, y-n+1); + return 0; +} +int SketcherPenXlant::draw_pixel(int x, int y) +{ + vfrm->draw_line(x-n, y+n, x+n, y-n); + vfrm->draw_line(x-n+1, y+n, x+n+1, y-n); + vfrm->draw_line(x-n, y+n+1, x+n, y-n+1); + vfrm->draw_line(x-n, y-n, x+n, y+n); + vfrm->draw_line(x-n+1, y-n, x+n+1, y+n); + vfrm->draw_line(x-n, y-n+1, x+n, y-n+1); + return 0; +} + + +VFrame *SketcherCurve::new_vpen(VFrame *out) +{ + switch( pen ) { + case PEN_SQUARE: return new SketcherPenSquare(out, radius); + case PEN_PLUS: return new SketcherPenPlus(out, radius); + case PEN_SLANT: return new SketcherPenSlant(out, radius); + case PEN_XLANT: return new SketcherPenXlant(out, radius); + } + return 0; +} + +void SketcherCurve::draw_line(VFrame *out) +{ + SketcherPoint *pt0 = points[0]; + VFrame *vpen = new_vpen(out); + out->set_pixel_color(color); + int n = points.size(); + if( n >= 2 ) { + for( int pi=1; pidraw_line(pt0->x, pt0->y, pt1->x, pt1->y); + pt0 = pt1; + } + } + else + vpen->draw_pixel(pt0->x, pt0->y); + delete vpen; +} + +/* +# python +from sympy import * +var("x,y, ax,ay, bx,by, cx,cy, dx,dy") + +var("abdx,abdy, acdx,acdy, bddx,bddy, cddx,cddy"); +abdx = bx-ax; abdy = by-ay; +acdx = cx-ax; acdy = cy-ay; +bddx = dx-bx; bddy = dy-by; +cddx = dx-cx; cddy = dy-cy; + +var("xc,yc, xd,yd, sx,sy"); +xc = (bx+dx)/2; yc = (by+dy)/2; +xd = cx-xc; yd = cy-yc; +ax = xc-xd; ay = yc-yd; +# line thru b with slope (c-a) intersects line thru c with slope (d-b) +sx = solve(((x - bx) * acdy/acdx + by) - ((x - cx) * bddy/bddx + cy),x) +sy = solve(((y - by) * acdx/acdy + bx) - ((y - cy) * bddx/bddy + cx),y) + +var("zx,zy, zdx,zdy, sx,sy, px,py, qx,qy"); +# point z = (b+c)/2 +zx = (bx+cx)/2; zy = (by+cy)/2; +zdx = (abdx+cddx)/2; zdy = (abdy+cddy)/2; +# line thru z with slope (d-a) intersects line thru b with slope (c-a) +px = solve(((x-zx)*zdy/zdx + zy) - ((x-bx) * acdy/acdx + by),x); +py = solve(((y-zy)*zdx/zdy + zx) - ((y-by) * acdx/acdy + bx),y); +# line thru z with slope (c-a + d-b)/2 intersects line thru c with slope (d-b) +qx = solve(((x-zx)*zdy/zdx + zy) - ((x-cx) * bddy/bddx + cy),x); +qy = solve(((y-zy)*zdx/zdy + zx) - ((y-cy) * bddx/bddy + cx),y); +*/ + +static void smooth_sxy( + float ax, float ay, float bx, float by, + float cx, float cy, float dx, float dy, + float &sx, float &sy) +{ + float acdx = cx-ax, acdy = cy-ay; + float bddx = dx-bx, bddy = dy-by; + float d = acdx*bddy - acdy*bddx; + if( fabsf(d) < 1 ) d = 1; + sx = (acdx*bddx*by - acdx*bddx*cy + acdx*bddy*cx - acdy*bddx*bx) / d; + sy = (acdx*bddy*by - acdy*bddx*cy - acdy*bddy*bx + acdy*bddy*cx) / d; + bclamp(sx, -32767.f, 32767.f); + bclamp(sy, -32767.f, 32767.f); +} + +static void smooth_pxy( + float ax, float ay, float bx, float by, + float cx, float cy, float dx, float dy, + float &px, float &py) +{ + float abdx = bx - ax, abdy = by - ay; + float acdx = cx - ax, acdy = cy - ay; + float cddx = dx - cx, cddy = dy - cy; + float d = (2*(abdx*acdy - abdy*acdx - acdx*cddy + acdy*cddx)); + if( fabsf(d) < 1 ) d = 1; + px = (-abdx*acdx*by + abdx*acdx*cy + 2*abdx*acdy*bx - abdy*acdx*bx - abdy*acdx*cx - + acdx*bx*cddy - acdx*by*cddx + acdx*cddx*cy - acdx*cddy*cx + 2*acdy*bx*cddx) / d; + py = (abdx*acdy*by + abdx*acdy*cy - 2*abdy*acdx*by + abdy*acdy*bx - abdy*acdy*cx - + 2*acdx*by*cddy + acdy*bx*cddy + acdy*by*cddx + acdy*cddx*cy - acdy*cddy*cx) / d; + bclamp(px, -32767.f, 32767.f); + bclamp(py, -32767.f, 32767.f); +} +static void smooth_qxy( + float ax, float ay, float bx, float by, + float cx, float cy, float dx, float dy, + float &qx, float &qy) +{ + float abdx = bx - ax, abdy = by - ay; + float bddx = dx - bx, bddy = dy - by; + float cddx = dx - cx, cddy = dy - cy; + float d = (2*(abdx*bddy - abdy*bddx - bddx*cddy + bddy*cddx)); + if( fabsf(d) < 1 ) d = 1; + qx = (abdx*bddx*by - abdx*bddx*cy + 2*abdx*bddy*cx - abdy*bddx*bx - abdy*bddx*cx - + bddx*bx*cddy + bddx*by*cddx - bddx*cddx*cy - bddx*cddy*cx + 2*bddy*cddx*cx) / d; + qy = (abdx*bddy*by + abdx*bddy*cy - 2*abdy*bddx*cy - abdy*bddy*bx + abdy*bddy*cx - + 2*bddx*cddy*cy - bddy*bx*cddy + bddy*by*cddx + bddy*cddx*cy + bddy*cddy*cx) / d; + bclamp(qx, -32767.f, 32767.f); + bclamp(qy, -32767.f, 32767.f); +} + + +static int convex(float ax,float ay, float bx,float by, + float cx,float cy, float dx,float dy) +{ + float abdx = bx - ax, abdy = by - ay; + float acdx = cx - ax, acdy = cy - ay; + float bcdx = cx - bx, bcdy = cy - by; + float bddx = dx - bx, bddy = dy - by; + float abc = abdx*acdy - abdy*acdx; + float bcd = bcdx*bddy - bcdy*bddx; + float v = abc * bcd; + return !v ? 0 : v>0 ? 1 : -1; +} + +void SketcherCurve::draw_smooth(VFrame *out) +{ + VFrame *vpen = new_vpen(out); + out->set_pixel_color(color); + int n = points.size(); + if( !n ) return; + if( n > 2 ) { + SketcherPoint *pt0 = points[0], *pt1 = points[1], *pt2 = points[2]; + float bx = pt0->x, by = pt0->y; + float cx = pt1->x, cy = pt1->y; + float dx = pt2->x, dy = pt2->y; + float xc = (bx+dx)/2.f, yc = (by+dy)/2.f; + float xd = cx - xc, yd = cy - yc; + float ax = xc - xd, ay = yc - yd; + float sx, sy; + for( int pi=0,n2=n-2; pix, dy = points[pi+2]->y; + if( convex(ax,ay, bx,by, cx,cy, dx,dy) >= 0 ) { + smooth_sxy(ax,ay, bx,by, cx,cy, dx,dy, sx, sy); + vpen->draw_smooth(bx,by, sx,sy, cx,cy); + } + else { + float zx = (bx+cx)/2.f, zy = (by+cy)/2.f; + smooth_pxy(ax,ay, bx,by, cx,cy, dx,dy, sx,sy); + vpen->draw_smooth(bx,by, sx,sy, zx,zy); + smooth_qxy(ax,ay, bx,by, cx,cy, dx,dy, sx,sy); + vpen->draw_smooth(zx,zy, sx,sy, cx,cy); + } + ax = bx; ay = by; + bx = cx; by = cy; + cx = dx; cy = dy; + } + xc = (ax+cx)/2.f; yc = (ay+cy)/2.f; + xd = bx - xc, yd = by - yc; + dx = xc - xd, dy = yc - yd; + smooth_sxy(ax, ay, bx, by, cx, cy, dx, dy, sx, sy); + vpen->draw_smooth(bx, by, sx, sy, cx, cy); + } + else if( n == 2 ) { + SketcherPoint *pt0 = points[0], *pt1 = points[1]; + vpen->draw_line(pt0->x, pt0->y, pt1->x, pt1->y); + } + else if( n > 0 ) { + SketcherPoint *pt0 = points[0]; + vpen->draw_pixel(pt0->x, pt0->y); + } + delete vpen; +} + +int Sketcher::process_realtime(VFrame *input, VFrame *output) +{ + this->input = input; this->output = output; + w = output->get_w(); h = output->get_h(); + if( input != output ) output->transfer_from(input); + + load_configuration(); + + for( int ci=0, n=config.curves.size(); cipoints.size(); + if( !m ) continue; + switch( cv->ty ) { + case TYP_OFF: + break; + case TYP_SKETCHER: + cv->draw_line(output); + break; + case TYP_SMOOTH: + cv->draw_smooth(output); + break; + } + } + + if( config.drag ) { + for( int ci=0, n=config.curves.size(); cipoints.size(); pipoints[pi], cv->color); + } + } + + return 0; +} + +void SketcherCurves::dump() +{ + for( int i=0; iid, cv_type[cv->ty], cv->radius, cv_pen[cv->pen], + (cv->color>>16)&0xff, (cv->color>>8)&0xff, (cv->color>>0)&0xff); + cv->points.dump(); + } +} +void SketcherPoints::dump() +{ + for( int i=0; iid, pt->x, pt->y); + } +} + diff --git a/cinelerra-5.1/plugins/sketcher/sketcher.h b/cinelerra-5.1/plugins/sketcher/sketcher.h new file mode 100644 index 00000000..d0429cb1 --- /dev/null +++ b/cinelerra-5.1/plugins/sketcher/sketcher.h @@ -0,0 +1,174 @@ +/* + * CINELERRA + * Copyright (C) 1997-2014 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + + +#ifndef __SKETCHERS_H__ +#define __SKETCHERS_H__ + +#include "pluginvclient.h" + +class Sketcher; + +enum { PT_ID, PT_X, PT_Y, PT_SZ }; +enum { CV_ID, CV_TY, CV_RAD, CV_PEN, CV_CLR, CV_SZ }; +enum { TYP_OFF, TYP_SKETCHER, TYP_SMOOTH, TYP_SZ }; +enum { PEN_SQUARE, PEN_PLUS, PEN_SLANT, PEN_XLANT, PEN_SZ }; + +class SketcherVPen : public VFrame +{ +public: + SketcherVPen(VFrame *vfrm, int n) + : VFrame(vfrm->get_data(), -1, vfrm->get_y()-vfrm->get_data(), + vfrm->get_u()-vfrm->get_data(), vfrm->get_v()-vfrm->get_data(), + vfrm->get_w(), vfrm->get_h(), vfrm->get_color_model(), + vfrm->get_bytes_per_line()) { + this->vfrm = vfrm; this->n = n; + } + virtual int draw_pixel(int x, int y) = 0; + VFrame *vfrm; + int n; +}; + +class SketcherPenSquare : public SketcherVPen +{ +public: + SketcherPenSquare(VFrame *vfrm, int n) : SketcherVPen(vfrm, n) {} + int draw_pixel(int x, int y); +}; +class SketcherPenPlus : public SketcherVPen +{ +public: + SketcherPenPlus(VFrame *vfrm, int n) : SketcherVPen(vfrm, n) {} + int draw_pixel(int x, int y); +}; +class SketcherPenSlant : public SketcherVPen +{ +public: + SketcherPenSlant(VFrame *vfrm, int n) : SketcherVPen(vfrm, n) {} + int draw_pixel(int x, int y); +}; +class SketcherPenXlant : public SketcherVPen +{ +public: + SketcherPenXlant(VFrame *vfrm, int n) : SketcherVPen(vfrm, n) {} + int draw_pixel(int x, int y); +}; + + +class SketcherPoint +{ +public: + int id; + int x, y; + + void init(int id, int x, int y); + SketcherPoint(int id, int x, int y); + SketcherPoint(int id=-1); + SketcherPoint(SketcherPoint &pt); + ~SketcherPoint(); + int equivalent(SketcherPoint &that); + void copy_from(SketcherPoint &that); + void save_data(FileXML &output); + void read_data(FileXML &input); +}; +class SketcherPoints : public ArrayList +{ +public: + SketcherPoints() {} + ~SketcherPoints() { remove_all_objects(); } + void dump(); +}; + +#define cv_type SketcherCurve::types +#define cv_pen SketcherCurve::pens + +class SketcherCurve +{ +public: + int id, ty, radius, pen, color; + static const char *types[TYP_SZ]; + static const char *pens[PEN_SZ]; + + SketcherPoints points; + + void init(int id, int ty, int radius, int pen, int color); + SketcherCurve(int id, int ty, int radius, int pen, int color); + SketcherCurve(int id=-1); + ~SketcherCurve(); + SketcherCurve(SketcherCurve &cv); + int equivalent(SketcherCurve &that); + void copy_from(SketcherCurve &that); + void save_data(FileXML &output); + void read_data(FileXML &input); + VFrame *new_vpen(VFrame *out); + void draw_line(VFrame *out); + void draw_smooth(VFrame *out); +}; +class SketcherCurves : public ArrayList +{ +public: + SketcherCurves() {} + ~SketcherCurves() { remove_all_objects(); } + void dump(); +}; + +class SketcherConfig +{ +public: + SketcherConfig(); + ~SketcherConfig(); + + SketcherCurves curves; + int equivalent(SketcherConfig &that); + void copy_from(SketcherConfig &that); + void interpolate(SketcherConfig &prev, SketcherConfig &next, + long prev_frame, long next_frame, long current_frame); + void limits(); + + int drag; + int cv_selected, pt_selected; +}; + +class Sketcher : public PluginVClient +{ +public: + Sketcher(PluginServer *server); + ~Sketcher(); +// required for all realtime plugins + PLUGIN_CLASS_MEMBERS2(SketcherConfig) + int is_realtime(); + void update_gui(); + void save_data(KeyFrame *keyframe); + void read_data(KeyFrame *keyframe); + int new_curve(int ty, int radius, int pen, int color); + int new_curve(); + int new_point(SketcherCurve *cv, int x, int y); + int new_point(); + int process_realtime(VFrame *input, VFrame *output); + static void draw_point(VFrame *vfrm, SketcherPoint *pt, int color, int d); + void draw_point(VFrame *vfrm, SketcherPoint *pt, int color); + + VFrame *input, *output; + int w, h, color_model, bpp, comp; + int is_yuv, is_float; +}; + +#endif diff --git a/cinelerra-5.1/plugins/sketcher/sketcherwindow.C b/cinelerra-5.1/plugins/sketcher/sketcherwindow.C new file mode 100644 index 00000000..5e55f29e --- /dev/null +++ b/cinelerra-5.1/plugins/sketcher/sketcherwindow.C @@ -0,0 +1,1218 @@ +/* + * CINELERRA + * Copyright (C) 2014 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include "automation.h" +#include "bcdisplayinfo.h" +#include "clip.h" +#include "sketcher.h" +#include "sketcherwindow.h" +#include "cstrdup.h" +#include "cwindow.h" +#include "cwindowgui.h" +#include "edl.h" +#include "edlsession.h" +#include "keys.h" +#include "language.h" +#include "mainerror.h" +#include "mwindow.h" +#include "plugin.h" +#include "pluginserver.h" +#include "theme.h" +#include "track.h" + +#define COLOR_W 30 +#define COLOR_H 30 + +const char *SketcherCurve::types[] = { + N_("off"), + N_("line"), + N_("smooth"), +}; +const char *SketcherCurve::pens[] = { + N_("box"), + N_("+"), + N_("/"), + N_("X"), +}; + +SketcherCurveTypeItem::SketcherCurveTypeItem(int ty) + : BC_MenuItem(_(cv_type[ty])) +{ + this->ty = ty; +} +int SketcherCurveTypeItem::handle_event() +{ + SketcherCurveType *popup = (SketcherCurveType*)get_popup_menu(); + popup->update(ty); + SketcherWindow *gui = popup->gui; + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + cv->ty = ty; + gui->curve_list->update(ci); + gui->send_configure_change(); + } + return 1; +} + +SketcherCurveType::SketcherCurveType(SketcherWindow *gui, int x, int y, int ty) + : BC_PopupMenu(x,y,64,_(cv_type[ty])) +{ + this->gui = gui; +} +void SketcherCurveType::create_objects() +{ + int n = sizeof(cv_type)/sizeof(cv_type[0]); + for( int ty=0; typen = pen; +} +int SketcherCurvePenItem::handle_event() +{ + SketcherCurvePen *popup = (SketcherCurvePen*)get_popup_menu(); + popup->update(pen); + SketcherWindow *gui = popup->gui; + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + cv->pen = pen; + gui->curve_list->update(ci); + gui->send_configure_change(); + } + return 1; +} + +SketcherCurvePen::SketcherCurvePen(SketcherWindow *gui, int x, int y, int pen) + : BC_PopupMenu(x,y,72,_(cv_pen[pen])) +{ + this->gui = gui; +} +void SketcherCurvePen::create_objects() +{ + int n = sizeof(cv_pen)/sizeof(cv_pen[0]); + for( int pen=0; pengui = gui; + this->color = BLACK; + for( int i=0; i<3; ++i ) { + vframes[i] = new VFrame(w, w, BC_RGBA8888); + vframes[i]->clear_frame(); + } +} + +SketcherCurveColor::~SketcherCurveColor() +{ + for( int i=0; i<3; ++i ) + delete vframes[i]; +} + +void SketcherCurveColor::set_color(int color) +{ + this->color = color; + int r = (color>>16) & 0xff; + int g = (color>>8) & 0xff; + int b = (color>>0) & 0xff; + for( int i=0; i<3; ++i ) { + VFrame *vframe = vframes[i]; + int ww = vframe->get_w(), hh = vframe->get_h(); + int cx = (ww+1)/2, cy = hh/2; + double cc = (cx*cx + cy*cy) / 4.; + uint8_t *bp = vframe->get_data(), *dp = bp; + uint8_t *ep = dp + vframe->get_data_size(); + int rr = r, gg = g, bb = b; + int bpl = vframe->get_bytes_per_line(); + switch( i ) { + case BUTTON_UP: + break; + case BUTTON_UPHI: + if( (rr+=48) > 0xff ) rr = 0xff; + if( (gg+=48) > 0xff ) gg = 0xff; + if( (bb+=48) > 0xff ) bb = 0xff; + break; + case BUTTON_DOWNHI: + if( (rr-=48) < 0x00 ) rr = 0x00; + if( (gg-=48) < 0x00 ) gg = 0x00; + if( (bb-=48) < 0x00 ) bb = 0x00; + break; + } + while( dp < ep ) { + int yy = (dp-bp) / bpl, xx = ((dp-bp) % bpl) >> 2; + int dy = cy - yy, dx = cx - xx; + double s = dx*dx + dy*dy - cc; + double ss = s < 0 ? 1 : s >= cc ? 0 : 1 - s/cc; + int aa = ss * 0xff; + *dp++ = rr; *dp++ = gg; *dp++ = bb; *dp++ = aa; + } + } + set_images(vframes); +} + +void SketcherCurveColor::update_gui(int color) +{ + set_color(color); + draw_face(); +} + +int SketcherCurveColor::handle_event() +{ + gui->start_color_thread(this); + return 1; +} + +SketcherCurveColorPicker::SketcherCurveColorPicker(SketcherWindow *gui, SketcherCurveColor *color_button) + : ColorPicker(0, _("Color")) +{ + this->gui = gui; + this->color_button = color_button; + this->color = 0; + color_update = new SketcherCurveColorThread(this); +} + +SketcherCurveColorPicker::~SketcherCurveColorPicker() +{ + delete color_update; +} + +void SketcherCurveColorPicker::start(int color) +{ + start_window(color, 0, 1); + color_update->start(); +} + +void SketcherCurveColorPicker::handle_done_event(int result) +{ + color_update->stop(); + gui->lock_window("SketcherCurveColorPicker::handle_done_event"); + if( result ) color = orig_color; + color_button->update_gui(color); + gui->unlock_window(); + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + cv->color = color; + gui->curve_list->update(ci); + gui->send_configure_change(); + } +} + +int SketcherCurveColorPicker::handle_new_color(int color, int alpha) +{ + this->color = color; + color_update->update_lock->unlock(); + return 1; +} + +void SketcherCurveColorPicker::update_gui() +{ + gui->lock_window("SketcherCurveColorPicker::update_gui"); + color_button->update_gui(color); + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 ) { + SketcherCurve *cv = config.curves[ci]; + cv->color = color; + gui->curve_list->update(ci); + gui->send_configure_change(); + } + gui->unlock_window(); +} + +SketcherCurveColorThread::SketcherCurveColorThread(SketcherCurveColorPicker *color_picker) + : Thread(1, 0, 0) +{ + this->color_picker = color_picker; + this->update_lock = new Condition(0,"SketcherCurveColorThread::update_lock"); + done = 1; +} + +SketcherCurveColorThread::~SketcherCurveColorThread() +{ + stop(); + delete update_lock; +} + +void SketcherCurveColorThread::start() +{ + if( done ) { + done = 0; + Thread::start(); + } +} + +void SketcherCurveColorThread::stop() +{ + if( !done ) { + done = 1; + update_lock->unlock(); + join(); + } +} + +void SketcherCurveColorThread::run() +{ + while( !done ) { + update_lock->lock("SketcherCurveColorThread::run"); + if( done ) break; + color_picker->update_gui(); + } +} + + +SketcherNum::SketcherNum(SketcherWindow *gui, int x, int y, int output, + int mn, int mx) + : BC_TumbleTextBox(gui, output, mn, mx, x, y, 64) +{ + this->gui = gui; + set_increment(1); +} + +SketcherNum::~SketcherNum() +{ +} + +int SketcherPointX::handle_event() +{ + if( !SketcherNum::handle_event() ) return 0; + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + SketcherPointList *point_list = gui->point_list; + int hot_point = point_list->get_selection_number(0, 0); + SketcherPoints &points = cv->points; + if( hot_point >= 0 && hot_point < points.size() ) { + int v = atoi(get_text()); + points[hot_point]->x = v; + point_list->set_point(hot_point, PT_X, v); + point_list->update_list(hot_point); + gui->send_configure_change(); + } + } + return 1; +} +int SketcherPointY::handle_event() +{ + if( !SketcherNum::handle_event() ) return 0; + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + SketcherPointList *point_list = gui->point_list; + int hot_point = point_list->get_selection_number(0, 0); + SketcherPoints &points = cv->points; + if( hot_point >= 0 && hot_point < points.size() ) { + int v = atoi(get_text()); + points[hot_point]->y = v; + point_list->set_point(hot_point, PT_Y, v); + point_list->update_list(hot_point); + gui->send_configure_change(); + } + } + return 1; +} + +int SketcherCurveRadius::handle_event() +{ + if( !SketcherNum::handle_event() ) return 0; + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + int v = atoi(get_text()); + cv->radius = v; + gui->curve_list->update(ci); + gui->send_configure_change(); + } + return 1; +} + + +SketcherWindow::SketcherWindow(Sketcher *plugin) + : PluginClientWindow(plugin, 380, 580, 380, 580, 0) +{ + this->plugin = plugin; + this->title_type = 0; this->curve_type = 0; + this->title_pen = 0; this->curve_pen = 0; + this->title_color = 0; this->curve_color = 0; + this->color_picker = 0; this->new_points = 0; + this->new_curve = 0; this->del_curve = 0; + this->curve_up = 0; this->curve_dn = 0; + this->title_x = 0; this->point_x = 0; + this->title_y = 0; this->point_y = 0; + this->new_point = 0; this->del_point = 0; + this->point_up = 0; this->point_dn = 0; + this->drag = 0; this->dragging = 0; + this->last_x = 0; this->last_y = 0; + this->point_list = 0; this->pending_config = 0; +} + +SketcherWindow::~SketcherWindow() +{ + delete curve_radius; + delete point_x; + delete point_y; + delete color_picker; +} + +void SketcherWindow::create_objects() +{ + int x = 10, y = 10, x1, y1; + int margin = plugin->get_theme()->widget_border; + BC_Title *title; + int ci = plugin->config.cv_selected; + if( ci < 0 || ci >= plugin->config.curves.size() ) + ci = plugin->new_curve(0, 1, 0, BLACK); + SketcherCurve *cv = plugin->config.curves[ci]; + add_subwindow(reset_curves = new SketcherResetCurves(this, plugin, x1=x, y+3)); + x1 += reset_curves->get_w() + 2*margin; + const char *curve_text = _("Curve"); + add_subwindow(title_radius = new BC_Title(x1, y, _("Width:"))); + x1 += title_radius->get_w() + margin; + curve_radius = new SketcherCurveRadius(this, x1, y, cv->radius); + curve_radius->create_objects(); + y += reset_curves->get_h() + 2*margin; + x1 = get_w()-x - BC_Title::calculate_w(this, curve_text, LARGEFONT); + y1 = y-margin - BC_Title::calculate_h(this, curve_text, LARGEFONT); + add_subwindow(title = new BC_Title(x1, y1, curve_text, LARGEFONT, + get_resources()->menu_highlighted_fontcolor)); + add_subwindow(curve_list = new SketcherCurveList(this, plugin, x, y)); + y += curve_list->get_h() + margin; + add_subwindow(title_type = new BC_Title(x, y, _("Type:"))); + x1 = x + title_type->get_w() + margin; + add_subwindow(curve_type = new SketcherCurveType(this, x1, y, cv->ty)); + curve_type->create_objects(); + x1 += curve_type->get_w() + margin; + add_subwindow(new_curve = new SketcherNewCurve(this, plugin, x1, y)); + x1 += new_curve->get_w() + margin; + add_subwindow(curve_up = new SketcherCurveUp(this, x1, y)); + x1 += curve_up->get_w() + 2*margin; + add_subwindow(title_color = new BC_Title(x1, y, _("Color:"))); + y += curve_type->get_h() + margin; + + add_subwindow(title_pen = new BC_Title(x, y, _("Pen:"))); + x1 = x + title_pen->get_w() + margin; + add_subwindow(curve_pen = new SketcherCurvePen(this, x1, y, cv->pen)); + curve_pen->create_objects(); + x1 += curve_pen->get_w() + margin; + add_subwindow(del_curve = new SketcherDelCurve(this, plugin, x1, y)); + x1 += del_curve->get_w() + margin; + add_subwindow(curve_dn = new SketcherCurveDn(this, x1, y)); + x1 += curve_dn->get_w() + 2*margin; + add_subwindow(curve_color = new SketcherCurveColor(this, x1, y, COLOR_W)); + curve_color->create_objects(); + curve_color->set_color(cv->color); + curve_color->draw_face(); + y += COLOR_H + margin; + curve_list->update(ci); + + BC_Bar *bar; + add_subwindow(bar = new BC_Bar(x, y, get_w()-2*x)); + y += bar->get_h() + 2*margin; + + int pi = plugin->config.pt_selected; + SketcherPoint *pt = pi >= 0 && pi < cv->points.size() ? cv->points[pi] : 0; + add_subwindow(reset_points = new SketcherResetPoints(this, plugin, x1=x, y+3)); + x1 += reset_points->get_w() + 2*margin; + add_subwindow(drag = new SketcherDrag(this, x1, y)); + y += drag->get_h() + margin; + if( plugin->config.drag ) { + if( !grab(plugin->server->mwindow->cwindow->gui) ) + eprintf("drag enabled, but compositor already grabbed\n"); + } + const char *point_text = _("Point"); + x1 = get_w()-x - BC_Title::calculate_w(this, point_text, LARGEFONT); + y1 = y-margin - BC_Title::calculate_h(this, point_text, LARGEFONT); + add_subwindow(title = new BC_Title(x1, y1, point_text, LARGEFONT, + get_resources()->menu_highlighted_fontcolor)); + add_subwindow(point_list = new SketcherPointList(this, plugin, x, y)); + + y += point_list->get_h() + margin; + add_subwindow(title_x = new BC_Title(x, y, _("X:"))); + x1 = x + title_x->get_w() + margin; + point_x = new SketcherPointX(this, x1, y, !pt ? 0.f : pt->x); + point_x->create_objects(); + x1 += point_x->get_w() + 2*margin; + add_subwindow(new_point = new SketcherNewPoint(this, plugin, x1, y)); + x1 += new_point->get_w() + margin; + add_subwindow(point_up = new SketcherPointUp(this, x1, y)); + y += point_x->get_h() + margin; + add_subwindow(title_y = new BC_Title(x, y, _("Y:"))); + x1 = x + title_y->get_w() + margin; + point_y = new SketcherPointY(this, x1, y, !pt ? 0.f : pt->y); + point_y->create_objects(); + x1 += point_y->get_w() + 2*margin; + add_subwindow(del_point = new SketcherDelPoint(this, plugin, x1, y)); + x1 += del_point->get_w() + margin; + add_subwindow(point_dn = new SketcherPointDn(this, x1, y)); + y += point_y->get_h() + margin + 10; + point_list->update(pi); + + add_subwindow(notes0 = new BC_Title(x, y, + _("\n" + "LMB=\n" + "Alt+LMB=\n" + "MMB=\n" + "DEL=\n"))); + add_subwindow(notes1 = new BC_Title(x+80, y, + _(" No Shift\n" + "select point\n" + "drag curve\n" + "next curve type\n" + "deletes point\n"))); + add_subwindow(notes2 = new BC_Title(x+200, y, + _(" Shift\n" + "append new points\n" + "drag image\n" + "append new curve\n" + "delete curve\n"))); + show_window(1); +} + +void SketcherWindow::send_configure_change() +{ + pending_config = 0; + plugin->send_configure_change(); +} + +int SketcherWindow::grab_event(XEvent *event) +{ + int ret = do_grab_event(event); + if( pending_config && !grab_event_count() ) + send_configure_change(); + return ret; +} + +int SketcherWindow::do_grab_event(XEvent *event) +{ + switch( event->type ) { + case ButtonPress: break; + case ButtonRelease: break; + case MotionNotify: break; + case KeyPress: + if( keysym_lookup(event) > 0 ) { + switch( get_keysym() ) { + case XK_Delete: + return (event->xkey.state & ShiftMask) ? + del_curve->handle_event() : + del_point->handle_event() ; + } + } // fall thru + default: + return 0; + } + + MWindow *mwindow = plugin->server->mwindow; + CWindowGUI *cwindow_gui = mwindow->cwindow->gui; + CWindowCanvas *canvas = cwindow_gui->canvas; + int cx, cy; cwindow_gui->get_relative_cursor(cx, cy); + cx -= mwindow->theme->ccanvas_x; + cy -= mwindow->theme->ccanvas_y; + + if( !dragging ) { + if( cx < 0 || cx >= mwindow->theme->ccanvas_w || + cy < 0 || cy >= mwindow->theme->ccanvas_h ) + return 0; + } + + switch( event->type ) { + case ButtonPress: + if( dragging ) return 0; + dragging = event->xbutton.state & Mod1Mask ? -1 : 1; // alt_down + break; + case ButtonRelease: + case MotionNotify: + if( !dragging ) return 0; + break; + default: + return 0; + } + + + int ci = plugin->config.cv_selected; + if( ci < 0 || ci >= plugin->config.curves.size() ) + return 1; + + float cursor_x = cx, cursor_y = cy; + canvas->canvas_to_output(mwindow->edl, 0, cursor_x, cursor_y); + int64_t position = plugin->get_source_position(); + float projector_x, projector_y, projector_z; + Track *track = plugin->server->plugin->track; + int track_w = track->track_w, track_h = track->track_h; + track->automation->get_projector( + &projector_x, &projector_y, &projector_z, + position, PLAY_FORWARD); + projector_x += mwindow->edl->session->output_w / 2; + projector_y += mwindow->edl->session->output_h / 2; + float output_x = (cursor_x - projector_x) / projector_z + track_w / 2; + float output_y = (cursor_y - projector_y) / projector_z + track_h / 2; + SketcherCurve *cv = plugin->config.curves[ci]; + SketcherPoints &points = cv->points; + int state = event->xmotion.state; + + switch( event->type ) { + case ButtonPress: { + if( dragging < 0 ) break; + int hot_point = -1; + int button_no = event->xbutton.button; + if( button_no == LEFT_BUTTON ) { +// create new point string + if( (state & ShiftMask) ) { + ++new_points; + hot_point = plugin->new_point(cv, output_x, output_y); + point_list->update(hot_point); + } + else { +// select point + int sz = points.size(); + int last_point = hot_point; + if( sz > 0 ) { + SketcherPoint *pt = points[hot_point=0]; + double dist = DISTANCE(output_x,output_y, pt->x,pt->y); + for( int i=1; ix,pt->y); + if( d >= dist ) continue; + dist = d; hot_point = i; + } + pt = points[hot_point]; + float px = (pt->x - track_w / 2) * projector_z + projector_x; + float py = (pt->y - track_h / 2) * projector_z + projector_y; + dist = DISTANCE(px, py, cursor_x,cursor_y); + if( dist >= HANDLE_W ) hot_point = -1; + } + if( hot_point != last_point ) { + SketcherPoint *pt = 0; + if( hot_point >= 0 && hot_point < sz ) { + pt = points[hot_point]; + point_list->set_point(hot_point, PT_X, pt->x = output_x); + point_list->set_point(hot_point, PT_Y, pt->y = output_y); + } + point_list->update_list(hot_point); + point_x->update(pt ? pt->x : 0.f); + point_y->update(pt ? pt->y : 0.f); + } + } + } + else if( button_no == MIDDLE_BUTTON ) { + if( (state & ShiftMask) ) { + int ci = plugin->new_curve(cv->ty, cv->radius, cv->pen, cv->color); + curve_list->update(ci); + point_list->update(-1); + } + else { + int ty = cv->ty + 1; + if( ty >= TYP_SZ ) ty = 0; + cv->ty = ty; + curve_type->update(ty); + curve_list->update(ci); + } + } + break; } + case MotionNotify: { + int hot_point = point_list->get_selection_number(0, 0); + if( dragging < 0 ) { + SketcherCurves &curves = plugin->config.curves; + int dx = round(output_x - last_x); + int dy = round(output_y - last_y); + int mnc = (state & ShiftMask) || ci<0 ? 0 : ci; + int mxc = (state & ShiftMask) ? curves.size() : ci+1; + for( int i=mnc; iconfig.curves[i]; + int pts = crv->points.size(); + for( int k=0; kpoints[k]; + pt->x += dx; pt->y += dy; + } + } + SketcherPoint *pt = hot_point >= 0 && hot_point < points.size() ? + points[hot_point] : 0; + point_x->update(pt ? pt->x : 0.f); + point_y->update(pt ? pt->y : 0.f); + point_list->update(hot_point); + break; + } + if( (state & Button1Mask) ) { + SketcherPoint *pt = hot_point >= 0 && hot_point < points.size() ? + points[hot_point] : 0; + if( pt && pt->x == output_x && pt->y == output_y ) break; + if( new_points ) { + if( pt ) { + float frac_w = DISTANCE(pt->x, pt->y, output_x, output_y) / get_w(); + if( frac_w < 0.01 ) break; // 1 percent w + } + if( (state & ShiftMask) ) { + ++new_points; + hot_point = plugin->new_point(cv, output_x, output_y); + point_list->update(hot_point); + } + } + else if( pt ) { + point_list->set_point(hot_point, PT_X, pt->x = output_x); + point_list->set_point(hot_point, PT_Y, pt->y = output_y); + point_list->update_list(hot_point); + point_x->update(pt->x); + point_y->update(pt->y); + } + } + break; } + case ButtonRelease: { + new_points = 0; + dragging = 0; + break; } + } + + last_x = output_x; last_y = output_y; + pending_config = 1; + return 1; +} + +int SketcherWindow::keypress_event() +{ + int key = get_keypress(); + switch( key ) { + case DELETE: return shift_down() ? + del_curve->handle_event() : + del_point->handle_event() ; + } + return 0; +} + +void SketcherWindow::done_event(int result) +{ + ungrab(client->server->mwindow->cwindow->gui); +} + +void SketcherWindow::start_color_thread(SketcherCurveColor *color_button) +{ + unlock_window(); + delete color_picker; + color_picker = new SketcherCurveColorPicker(this, color_button); + int color = BLACK, ci = plugin->config.cv_selected; + if( ci >= 0 && ci < plugin->config.curves.size() ) { + SketcherCurve *cv = plugin->config.curves[ci]; + color = cv->color; + } + color_picker->start(color); + lock_window("SketcherWindow::start_color_thread"); +} + + +SketcherCurveList::SketcherCurveList(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT) +{ + this->gui = gui; + this->plugin = plugin; + titles[CV_ID] = _("id"); widths[CV_ID] = 64; + titles[CV_TY] = _("type"); widths[CV_TY] = 64; + titles[CV_RAD] = _("radius"); widths[CV_RAD] = 64; + titles[CV_PEN] = _("pen"); widths[CV_PEN] = 64; + titles[CV_CLR] = _("color"); widths[CV_CLR] = 64; +} +SketcherCurveList::~SketcherCurveList() +{ + clear(); +} +void SketcherCurveList::clear() +{ + for( int i=CV_SZ; --i>=0; ) + cols[i].remove_all_objects(); +} + +int SketcherCurveList::column_resize_event() +{ + for( int i=CV_SZ; --i>=0; ) + widths[i] = get_column_width(i); + return 1; +} + +int SketcherCurveList::handle_event() +{ + int ci = get_selection_number(0, 0); + set_selected(ci); + gui->point_list->update(0); + gui->send_configure_change(); + return 1; +} + +int SketcherCurveList::selection_changed() +{ + handle_event(); + return 1; +} + +void SketcherCurveList::set_selected(int k) +{ + int ci = -1; + if( k >= 0 && k < plugin->config.curves.size() ) { + SketcherCurve *cv = plugin->config.curves[k]; + gui->curve_type->update(cv->ty); + gui->curve_radius->update(cv->radius); + gui->curve_pen->update(cv->pen); + gui->curve_color->update_gui(cv->color); + ci = k; + } + plugin->config.cv_selected = ci; + update_selection(&cols[0], ci); + update_list(-1); +} + +void SketcherCurveList::update_list(int k) +{ + int xpos = get_xposition(), ypos = get_yposition(); + if( k < 0 ) k = get_selection_number(0, 0); + update_selection(&cols[0], k); + BC_ListBox::update(&cols[0], &titles[0],&widths[0],CV_SZ, xpos,ypos,k); + center_selection(); +} + +void SketcherCurveList::update(int k) +{ + clear(); + SketcherCurves &curves = plugin->config.curves; + int sz = curves.size(); + for( int i=0; iid); + char ttxt[BCSTRLEN]; sprintf(ttxt,"%s", cv_type[cv->ty]); + char rtxt[BCSTRLEN]; sprintf(rtxt,"%d", cv->radius); + char ptxt[BCSTRLEN]; sprintf(ptxt,"%s", cv_pen[cv->pen]); + int color = cv->color; + int r = (color>>16)&0xff, g = (color>>8)&0xff, b = (color>>0)&0xff; + char ctxt[BCSTRLEN]; sprintf(ctxt,"#%02x%02x%02x", r, g, b); + add_curve(itxt, ttxt, rtxt, ptxt, ctxt); + } + set_selected(k); +} + +void SketcherCurveList::add_curve(const char *id, const char *type, + const char *radius, const char *pen, const char *color) +{ + cols[CV_ID].append(new BC_ListBoxItem(id)); + cols[CV_TY].append(new BC_ListBoxItem(type)); + cols[CV_RAD].append(new BC_ListBoxItem(radius)); + cols[CV_PEN].append(new BC_ListBoxItem(pen)); + cols[CV_CLR].append(new BC_ListBoxItem(color)); +} + +SketcherNewCurve::SketcherNewCurve(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_GenericButton(x, y, 64, _("New")) +{ + this->gui = gui; + this->plugin = plugin; +} +SketcherNewCurve::~SketcherNewCurve() +{ +} +int SketcherNewCurve::handle_event() +{ + int ty = 1, pen = 0, color = 0, radius = 1; + int ci = plugin->config.cv_selected; + if( ci >= 0 && ci < plugin->config.curves.size() ) { + SketcherCurve *cv = plugin->config.curves[ci]; + ty = cv->ty; pen = cv->pen; + color = cv->color; radius = cv->radius; + } + int k = plugin->new_curve(ty, radius, pen, color); + gui->curve_list->update(k); + gui->point_list->update(-1); + gui->send_configure_change(); + return 1; +} + +SketcherDelCurve::SketcherDelCurve(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_GenericButton(x, y, 64, C_("Del")) +{ + this->gui = gui; + this->plugin = plugin; +} +SketcherDelCurve::~SketcherDelCurve() +{ +} +int SketcherDelCurve::handle_event() +{ + int hot_curve = gui->curve_list->get_selection_number(0, 0); + SketcherCurves &curves = plugin->config.curves; + if( hot_curve >= 0 && hot_curve < curves.size() ) { + curves.remove_object_number(hot_curve); + if( --hot_curve < 0 ) + hot_curve = plugin->new_curve(0, 1, 0, BLACK); + gui->curve_list->update(hot_curve); + gui->point_list->update(-1); + gui->send_configure_change(); + } + return 1; +} + +SketcherCurveUp::SketcherCurveUp(SketcherWindow *gui, int x, int y) + : BC_GenericButton(x, y, _("Up")) +{ + this->gui = gui; +} +SketcherCurveUp::~SketcherCurveUp() +{ +} + +int SketcherCurveUp::handle_event() +{ + SketcherCurves &curves = gui->plugin->config.curves; + int hot_curve = gui->curve_list->get_selection_number(0, 0); + + if( hot_curve > 0 && hot_curve < curves.size() ) { + SketcherCurve *&cv0 = curves[hot_curve]; + SketcherCurve *&cv1 = curves[--hot_curve]; + SketcherCurve *t = cv0; cv0 = cv1; cv1 = t; + gui->curve_list->update(hot_curve); + } + gui->send_configure_change(); + return 1; +} + +SketcherCurveDn::SketcherCurveDn(SketcherWindow *gui, int x, int y) + : BC_GenericButton(x, y, _("Dn")) +{ + this->gui = gui; +} +SketcherCurveDn::~SketcherCurveDn() +{ +} + +int SketcherCurveDn::handle_event() +{ + SketcherCurves &curves = gui->plugin->config.curves; + int hot_curve = gui->curve_list->get_selection_number(0, 0); + + if( hot_curve >= 0 && hot_curve < curves.size()-1 ) { + SketcherCurve *&cv0 = curves[hot_curve]; + SketcherCurve *&cv1 = curves[++hot_curve]; + SketcherCurve *t = cv0; cv0 = cv1; cv1 = t; + gui->curve_list->update(hot_curve); + } + gui->send_configure_change(); + return 1; +} + + +SketcherPointList::SketcherPointList(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_ListBox(x, y, 360, 130, LISTBOX_TEXT) +{ + this->gui = gui; + this->plugin = plugin; + titles[PT_X] = _("X"); widths[PT_X] = 90; + titles[PT_Y] = _("Y"); widths[PT_Y] = 90; + titles[PT_ID] = _("ID"); widths[PT_ID] = 50; +} +SketcherPointList::~SketcherPointList() +{ + clear(); +} +void SketcherPointList::clear() +{ + for( int i=PT_SZ; --i>=0; ) + cols[i].remove_all_objects(); +} + +int SketcherPointList::column_resize_event() +{ + for( int i=PT_SZ; --i>=0; ) + widths[i] = get_column_width(i); + return 1; +} + +int SketcherPointList::handle_event() +{ + int pi = get_selection_number(0, 0); + set_selected(pi); + gui->send_configure_change(); + return 1; +} + +int SketcherPointList::selection_changed() +{ + handle_event(); + return 1; +} + +void SketcherPointList::add_point(const char *id, const char *xp, const char *yp) +{ + cols[PT_ID].append(new BC_ListBoxItem(id)); + cols[PT_X].append(new BC_ListBoxItem(xp)); + cols[PT_Y].append(new BC_ListBoxItem(yp)); +} + +void SketcherPointList::set_point(int i, int c, int v) +{ + char stxt[BCSTRLEN]; + sprintf(stxt,"%d",v); + set_point(i,c,stxt); +} +void SketcherPointList::set_point(int i, int c, const char *cp) +{ + cols[c].get(i)->set_text(cp); +} + +void SketcherPointList::set_selected(int k) +{ + SketcherPoint *pt = 0; + int ci = plugin->config.cv_selected, pi = -1; + if( ci >= 0 && ci < plugin->config.curves.size() ) { + SketcherCurve *cv = plugin->config.curves[ci]; + pt = k >= 0 && k < cv->points.size() ? cv->points[pi=k] : 0; + } + gui->point_x->update(pt ? pt->x : 0.f); + gui->point_y->update(pt ? pt->y : 0.f); + plugin->config.pt_selected = pi; + update_selection(&cols[0], pi); + update_list(k); +} +void SketcherPointList::update_list(int k) +{ + int xpos = get_xposition(), ypos = get_yposition(); + if( k < 0 ) k = get_selection_number(0, 0); + update_selection(&cols[0], k); + BC_ListBox::update(&cols[0], &titles[0],&widths[0],PT_SZ, xpos,ypos,k); + center_selection(); +} +void SketcherPointList::update(int k) +{ + clear(); + int ci = plugin->config.cv_selected, sz = 0; + if( ci >= 0 && ci < plugin->config.curves.size() ) { + SketcherCurve *cv = plugin->config.curves[ci]; + SketcherPoints &points = cv->points; + sz = points.size(); + for( int i=0; iid); + char xtxt[BCSTRLEN]; sprintf(xtxt,"%d", pt->x); + char ytxt[BCSTRLEN]; sprintf(ytxt,"%d", pt->y); + add_point(itxt, xtxt, ytxt); + } + } + set_selected(k); +} + +void SketcherWindow::update_gui() +{ + SketcherConfig &config = plugin->config; + int ci = config.cv_selected; + int pi = config.pt_selected; + curve_list->update(ci); + point_list->update(pi); + SketcherCurve *cv = ci >= 0 ? config.curves[ci] : 0; + curve_radius->update(cv ? cv->radius : 1); + curve_type->update(cv ? cv->ty : TYP_OFF); + curve_pen->update(cv ? cv->pen : PEN_SQUARE); + curve_color->set_color(cv ? cv->color : BLACK); + SketcherPoint *pt = pi >= 0 ? cv->points[pi] : 0; + point_x->update(pt ? pt->x : 0); + point_y->update(pt ? pt->y : 0); + drag->update(plugin->config.drag); +} + + +SketcherPointUp::SketcherPointUp(SketcherWindow *gui, int x, int y) + : BC_GenericButton(x, y, _("Up")) +{ + this->gui = gui; +} +SketcherPointUp::~SketcherPointUp() +{ +} + +int SketcherPointUp::handle_event() +{ + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci < 0 || ci >= config.curves.size() ) + return 1; + SketcherCurve *cv = config.curves[ci]; + SketcherPoints &points = cv->points; + int sz = points.size(); + int hot_point = gui->point_list->get_selection_number(0, 0); + + if( sz > 1 && hot_point > 0 ) { + SketcherPoint *&pt0 = points[hot_point]; + SketcherPoint *&pt1 = points[--hot_point]; + SketcherPoint *t = pt0; pt0 = pt1; pt1 = t; + gui->point_list->update(hot_point); + } + gui->send_configure_change(); + return 1; +} + +SketcherPointDn::SketcherPointDn(SketcherWindow *gui, int x, int y) + : BC_GenericButton(x, y, _("Dn")) +{ + this->gui = gui; +} +SketcherPointDn::~SketcherPointDn() +{ +} + +int SketcherPointDn::handle_event() +{ + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci < 0 || ci >= config.curves.size() ) + return 1; + SketcherCurve *cv = config.curves[ci]; + SketcherPoints &points = cv->points; + int sz = points.size(); + int hot_point = gui->point_list->get_selection_number(0, 0); + if( sz > 1 && hot_point < sz-1 ) { + SketcherPoint *&pt0 = points[hot_point]; + SketcherPoint *&pt1 = points[++hot_point]; + SketcherPoint *t = pt0; pt0 = pt1; pt1 = t; + gui->point_list->update(hot_point); + } + gui->send_configure_change(); + return 1; +} + +SketcherDrag::SketcherDrag(SketcherWindow *gui, int x, int y) + : BC_CheckBox(x, y, gui->plugin->config.drag, _("Drag")) +{ + this->gui = gui; +} +int SketcherDrag::handle_event() +{ + CWindowGUI *cwindow_gui = gui->plugin->server->mwindow->cwindow->gui; + int value = get_value(); + if( value ) { + if( !gui->grab(cwindow_gui) ) { + update(value = 0); + flicker(10,50); + } + } + else + gui->ungrab(cwindow_gui); + gui->plugin->config.drag = value; + gui->send_configure_change(); + return 1; +} + +SketcherNewPoint::SketcherNewPoint(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_GenericButton(x, y, 64, _("New")) +{ + this->gui = gui; + this->plugin = plugin; +} +SketcherNewPoint::~SketcherNewPoint() +{ +} +int SketcherNewPoint::handle_event() +{ + int k = plugin->new_point(); + gui->point_list->update(k); + gui->send_configure_change(); + return 1; +} + +SketcherDelPoint::SketcherDelPoint(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_GenericButton(x, y, 64, C_("Del")) +{ + this->gui = gui; + this->plugin = plugin; +} +SketcherDelPoint::~SketcherDelPoint() +{ +} +int SketcherDelPoint::handle_event() +{ + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + SketcherPoints &points = cv->points; + int hot_point = gui->point_list->get_selection_number(0, 0); + if( hot_point >= 0 && hot_point < points.size() ) { + points.remove_object_number(hot_point); + gui->point_list->update(--hot_point); + gui->send_configure_change(); + } + } + return 1; +} + +SketcherResetCurves::SketcherResetCurves(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_GenericButton(x, y, _("Reset")) +{ + this->gui = gui; + this->plugin = plugin; +} +SketcherResetCurves::~SketcherResetCurves() +{ +} +int SketcherResetCurves::handle_event() +{ + SketcherConfig &config = plugin->config; + config.curves.remove_all_objects(); + int ci = plugin->new_curve(0, 1, 0, BLACK); + gui->curve_list->update(ci); + gui->point_list->update(-1); + gui->send_configure_change(); + return 1; +} + +SketcherResetPoints::SketcherResetPoints(SketcherWindow *gui, Sketcher *plugin, int x, int y) + : BC_GenericButton(x, y, _("Reset")) +{ + this->gui = gui; + this->plugin = plugin; +} +SketcherResetPoints::~SketcherResetPoints() +{ +} +int SketcherResetPoints::handle_event() +{ + SketcherConfig &config = gui->plugin->config; + int ci = config.cv_selected; + if( ci >= 0 && ci < config.curves.size() ) { + SketcherCurve *cv = config.curves[ci]; + cv->points.remove_all_objects(); + gui->point_list->update(-1); + gui->send_configure_change(); + } + return 1; +} + diff --git a/cinelerra-5.1/plugins/sketcher/sketcherwindow.h b/cinelerra-5.1/plugins/sketcher/sketcherwindow.h new file mode 100644 index 00000000..a0cc4ae2 --- /dev/null +++ b/cinelerra-5.1/plugins/sketcher/sketcherwindow.h @@ -0,0 +1,401 @@ +/* + * CINELERRA + * Copyright (C) 2008-2015 Adam Williams + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __CRIKEYWINDOW_H__ +#define __CRIKEYWINDOW_H__ + +#include "guicast.h" +#include "colorpicker.h" + +class Sketcher; +class SketcherNum; +class SketcherCurveTypeItem; +class SketcherCurveType; +class SketcherCurvePenItem; +class SketcherCurvePen; +class SketcherCurveColor; +class SketcherCurveColorPicker; +class SketcherCurveColorThread; +class SketcherNewCurve; +class SketcherDelCurve; +class SketcherCurveUp; +class SketcherCurveDn; +class SketcherCurveRadius; +class SketcherCurveList; +class SketcherPointX; +class SketcherPointY; +class SketcherDrag; +class SketcherPointList; +class SketcherNewPoint; +class SketcherDelPoint; +class SketcherPointUp; +class SketcherPointDn; +class SketcherResetCurves; +class SketcherResetPoints; +class SketcherWindow; + +class SketcherNum : public BC_TumbleTextBox +{ +public: + SketcherWindow *gui; + + SketcherNum(SketcherWindow *gui, int x, int y, int output, + int mn=-32767, int mx=32767); + ~SketcherNum(); + int update(int v) { return BC_TumbleTextBox::update((int64_t)v); } +}; + +class SketcherCurveTypeItem : public BC_MenuItem +{ +public: + SketcherCurveTypeItem(int ty); + int handle_event(); + int ty; +}; + +class SketcherCurveType : public BC_PopupMenu +{ +public: + SketcherCurveType(SketcherWindow *gui, int x, int y, int ty); + void create_objects(); + void update(int ty); + + SketcherWindow *gui; +}; + +class SketcherCurvePenItem : public BC_MenuItem +{ +public: + SketcherCurvePenItem(int pen); + int handle_event(); + int pen; +}; + +class SketcherCurvePen : public BC_PopupMenu +{ +public: + SketcherCurvePen(SketcherWindow *gui, int x, int y, int pen); + void create_objects(); + void update(int ty); + + SketcherWindow *gui; +}; + +class SketcherCurveColor : public BC_Button +{ +public: + SketcherCurveColor(SketcherWindow *gui, int x, int y, int w); + ~SketcherCurveColor(); + + void set_color(int color); + void update_gui(int color); + int handle_event(); + + int color; + VFrame *vframes[3]; + SketcherWindow *gui; +}; + +class SketcherCurveColorPicker : public ColorPicker +{ +public: + SketcherCurveColorPicker(SketcherWindow *gui, SketcherCurveColor *curve_color); + ~SketcherCurveColorPicker(); + void start(int color); + int handle_new_color(int color, int alpha); + void update_gui(); + void handle_done_event(int result); + + SketcherWindow *gui; + int color; + SketcherCurveColor *color_button; + SketcherCurveColorThread *color_update; +}; + +class SketcherCurveColorThread : public Thread +{ +public: + SketcherCurveColorThread(SketcherCurveColorPicker *color_picker); + ~SketcherCurveColorThread(); + + void start(); + void stop(); + void run(); + + SketcherCurveColorPicker *color_picker; + int done; + Condition *update_lock; +}; + +class SketcherNewCurve : public BC_GenericButton +{ +public: + SketcherNewCurve(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherNewCurve(); + + int handle_event(); + + SketcherWindow *gui; + Sketcher *plugin; +}; + +class SketcherDelCurve : public BC_GenericButton +{ +public: + SketcherDelCurve(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherDelCurve(); + + int handle_event(); + + Sketcher *plugin; + SketcherWindow *gui; +}; + +class SketcherCurveUp : public BC_GenericButton +{ +public: + SketcherCurveUp(SketcherWindow *gui, int x, int y); + ~SketcherCurveUp(); + + int handle_event(); + + SketcherWindow *gui; +}; + +class SketcherCurveDn : public BC_GenericButton +{ +public: + SketcherCurveDn(SketcherWindow *gui, int x, int y); + ~SketcherCurveDn(); + + int handle_event(); + + SketcherWindow *gui; +}; + +class SketcherCurveRadius : public SketcherNum +{ +public: + SketcherCurveRadius(SketcherWindow *gui, int x, int y, float output) + : SketcherNum(gui, x, y, output, 0, 255) {} + ~SketcherCurveRadius() {} + + int handle_event(); +}; + +class SketcherCurveList : public BC_ListBox +{ +public: + SketcherCurveList(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherCurveList(); + + int handle_event(); + int selection_changed(); + int column_resize_event(); + ArrayList cols[CV_SZ]; + void clear(); + void add_curve(const char *id, const char *type, + const char *radius, const char *pen, const char *color); + void del_curve(int i); + void set_selected(int k); + void update(int k); + void update_list(int k); + + SketcherWindow *gui; + Sketcher *plugin; + const char *titles[CV_SZ]; + int widths[CV_SZ]; +}; + + +class SketcherPointX : public SketcherNum +{ +public: + SketcherPointX(SketcherWindow *gui, int x, int y, float output) + : SketcherNum(gui, x, y, output) {} + ~SketcherPointX() {} + + int handle_event(); +}; +class SketcherPointY : public SketcherNum +{ +public: + SketcherPointY(SketcherWindow *gui, int x, int y, float output) + : SketcherNum(gui, x, y, output) {} + ~SketcherPointY() {} + + int handle_event(); +}; + + +class SketcherDrag : public BC_CheckBox +{ +public: + SketcherDrag(SketcherWindow *gui, int x, int y); + + int handle_event(); + SketcherWindow *gui; +}; + + +class SketcherPointList : public BC_ListBox +{ +public: + SketcherPointList(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherPointList(); + + int handle_event(); + int selection_changed(); + int column_resize_event(); + ArrayList cols[PT_SZ]; + void clear(); + void add_point(const char *id, const char *xp, const char *yp); + void set_point(int i, int c, int v); + void set_point(int i, int c, const char *cp); + void set_selected(int k); + void update(int k); + void update_list(int k); + + + SketcherWindow *gui; + Sketcher *plugin; + const char *titles[PT_SZ]; + int widths[PT_SZ]; +}; + +class SketcherNewPoint : public BC_GenericButton +{ +public: + SketcherNewPoint(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherNewPoint(); + + int handle_event(); + + SketcherWindow *gui; + Sketcher *plugin; +}; + +class SketcherDelPoint : public BC_GenericButton +{ +public: + SketcherDelPoint(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherDelPoint(); + + int handle_event(); + + Sketcher *plugin; + SketcherWindow *gui; +}; + +class SketcherPointUp : public BC_GenericButton +{ +public: + SketcherPointUp(SketcherWindow *gui, int x, int y); + ~SketcherPointUp(); + + int handle_event(); + + SketcherWindow *gui; +}; + +class SketcherPointDn : public BC_GenericButton +{ +public: + SketcherPointDn(SketcherWindow *gui, int x, int y); + ~SketcherPointDn(); + + int handle_event(); + + SketcherWindow *gui; +}; + +class SketcherResetCurves : public BC_GenericButton +{ +public: + SketcherResetCurves(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherResetCurves(); + + int handle_event(); + + Sketcher *plugin; + SketcherWindow *gui; +}; + +class SketcherResetPoints : public BC_GenericButton +{ +public: + SketcherResetPoints(SketcherWindow *gui, Sketcher *plugin, int x, int y); + ~SketcherResetPoints(); + + int handle_event(); + + Sketcher *plugin; + SketcherWindow *gui; +}; + + +class SketcherWindow : public PluginClientWindow +{ +public: + SketcherWindow(Sketcher *plugin); + ~SketcherWindow(); + + void create_objects(); + void update_gui(); + void start_color_thread(SketcherCurveColor *curve_color); + int grab_event(XEvent *event); + int do_grab_event(XEvent *event); + void done_event(int result); + void send_configure_change(); + int keypress_event(); + + Sketcher *plugin; + + BC_Title *title_type, *title_pen; + BC_Title *title_color, *title_radius; + SketcherCurveType *curve_type; + SketcherCurvePen *curve_pen; + SketcherCurveColor *curve_color; + SketcherCurveColorPicker *color_picker; + SketcherNewCurve *new_curve; + SketcherDelCurve *del_curve; + SketcherCurveUp *curve_up; + SketcherCurveDn *curve_dn; + SketcherCurveRadius *curve_radius; + SketcherCurveList *curve_list; + SketcherResetCurves *reset_curves; + + BC_Title *title_x, *title_y; + SketcherPointX *point_x; + SketcherPointY *point_y; + SketcherNewPoint *new_point; + SketcherDelPoint *del_point; + SketcherPointUp *point_up; + SketcherPointDn *point_dn; + int dragging, pending_config; + int new_points; + float last_x, last_y; + SketcherDrag *drag; + SketcherPointList *point_list; + SketcherResetPoints *reset_points; + BC_Title *notes0, *notes1, *notes2; +}; +#endif + diff --git a/cinelerra-5.1/plugins/titler/titlerwindow.C b/cinelerra-5.1/plugins/titler/titlerwindow.C index bddb7993..c34e2903 100644 --- a/cinelerra-5.1/plugins/titler/titlerwindow.C +++ b/cinelerra-5.1/plugins/titler/titlerwindow.C @@ -785,7 +785,7 @@ TitleColorButton::TitleColorButton(TitleMain *client, TitleWindow *window, int x int TitleColorButton::handle_event() { window->color_thread->start_window(client->config.color, - client->config.alpha); + client->config.alpha, 1); return 1; } TitleOutlineColorButton::TitleOutlineColorButton(TitleMain *client, TitleWindow *window, int x, int y) @@ -797,7 +797,7 @@ TitleOutlineColorButton::TitleOutlineColorButton(TitleMain *client, TitleWindow int TitleOutlineColorButton::handle_event() { window->outline_color_thread->start_window(client->config.outline_color, - client->config.outline_alpha); + client->config.outline_alpha, 1); return 1; } @@ -1234,6 +1234,17 @@ int TitleColorThread::handle_new_color(int output, int alpha) return 1; } +void TitleColorThread::handle_done_event(int result) +{ + if( result ) { + client->config.color = orig_color; + client->config.alpha = orig_alpha; + handle_new_color(orig_color, orig_alpha); + window->update_color(); + window->send_configure_change(); + } +} + TitleDrag::TitleDrag(TitleMain *client, TitleWindow *window, int x, int y) : DragCheckBox(client->server->mwindow, x, y, _("Drag"), &client->config.drag, client->config.title_x, client->config.title_y, @@ -1528,9 +1539,10 @@ int TitleColorPopup::activate() } void TitleColorPopup::handle_done_event(int result) { - if( result ) return; - char txt[BCSTRLEN]; sprintf(txt, "<%s #%06x>", _(KW_COLOR), color_value); - window->insert_ibeam(txt); + if( !result ) { + char txt[BCSTRLEN]; sprintf(txt, "<%s #%06x>", _(KW_COLOR), color_value); + window->insert_ibeam(txt); + } } TitlePngPopup::TitlePngPopup(TitleMain *client, TitleWindow *window) diff --git a/cinelerra-5.1/plugins/titler/titlerwindow.h b/cinelerra-5.1/plugins/titler/titlerwindow.h index 99cd3e18..4dcaa6dd 100644 --- a/cinelerra-5.1/plugins/titler/titlerwindow.h +++ b/cinelerra-5.1/plugins/titler/titlerwindow.h @@ -503,6 +503,7 @@ class TitleColorThread : public ColorPicker public: TitleColorThread(TitleMain *client, TitleWindow *window, int is_outline); virtual int handle_new_color(int output, int alpha); + void handle_done_event(int result); TitleMain *client; TitleWindow *window; int is_outline; diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch0 b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch0 similarity index 100% rename from cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch0 rename to cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch0 diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch1 b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch1 similarity index 100% rename from cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch1 rename to cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch1 diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch2 b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch2 similarity index 100% rename from cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch2 rename to cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch2 diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch3 b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch3 similarity index 81% rename from cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch3 rename to cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch3 index 3d64695a..6e2ebbcd 100644 --- a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.patch3 +++ b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.patch3 @@ -1,6 +1,6 @@ diff -urN a/libavformat/avformat.h b/libavformat/avformat.h ---- a/libavformat/avformat.h 2018-04-20 04:02:57.000000000 -0600 -+++ b/libavformat/avformat.h 2018-04-24 11:02:20.777232001 -0600 +--- a/libavformat/avformat.h 2018-11-05 16:22:26.000000000 -0700 ++++ b/libavformat/avformat.h 2018-11-08 07:25:17.066799941 -0700 @@ -487,6 +487,9 @@ The user or muxer can override this through AVFormatContext.avoid_negative_ts @@ -22,8 +22,8 @@ diff -urN a/libavformat/avformat.h b/libavformat/avformat.h int flags; diff -urN a/libavformat/dv.c b/libavformat/dv.c ---- a/libavformat/dv.c 2018-04-13 17:34:28.000000000 -0600 -+++ b/libavformat/dv.c 2018-04-24 11:02:20.778232001 -0600 +--- a/libavformat/dv.c 2018-11-01 12:34:26.000000000 -0600 ++++ b/libavformat/dv.c 2018-11-08 07:25:17.066799941 -0700 @@ -632,6 +632,7 @@ AVInputFormat ff_dv_demuxer = { .name = "dv", @@ -33,9 +33,9 @@ diff -urN a/libavformat/dv.c b/libavformat/dv.c .read_probe = dv_probe, .read_header = dv_read_header, diff -urN a/libavformat/matroskadec.c b/libavformat/matroskadec.c ---- a/libavformat/matroskadec.c 2018-04-20 04:02:57.000000000 -0600 -+++ b/libavformat/matroskadec.c 2018-04-24 11:02:20.779232001 -0600 -@@ -4026,6 +4026,7 @@ +--- a/libavformat/matroskadec.c 2018-11-05 16:22:26.000000000 -0700 ++++ b/libavformat/matroskadec.c 2018-11-08 07:25:17.067799930 -0700 +@@ -4030,6 +4030,7 @@ AVInputFormat ff_matroska_demuxer = { .name = "matroska,webm", .long_name = NULL_IF_CONFIG_SMALL("Matroska / WebM"), @@ -43,7 +43,7 @@ diff -urN a/libavformat/matroskadec.c b/libavformat/matroskadec.c .extensions = "mkv,mk3d,mka,mks", .priv_data_size = sizeof(MatroskaDemuxContext), .read_probe = matroska_probe, -@@ -4039,6 +4040,7 @@ +@@ -4043,6 +4044,7 @@ AVInputFormat ff_webm_dash_manifest_demuxer = { .name = "webm_dash_manifest", .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"), @@ -52,9 +52,9 @@ diff -urN a/libavformat/matroskadec.c b/libavformat/matroskadec.c .read_header = webm_dash_manifest_read_header, .read_packet = webm_dash_manifest_read_packet, diff -urN a/libavformat/utils.c b/libavformat/utils.c ---- a/libavformat/utils.c 2018-04-20 04:02:58.000000000 -0600 -+++ b/libavformat/utils.c 2018-04-24 11:02:20.780232001 -0600 -@@ -2471,6 +2471,13 @@ +--- a/libavformat/utils.c 2018-11-05 16:22:26.000000000 -0700 ++++ b/libavformat/utils.c 2018-11-08 07:25:17.069799908 -0700 +@@ -2472,6 +2472,13 @@ return seek_frame_byte(s, stream_index, timestamp, flags); } diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.tar.xz b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.tar.xz similarity index 52% rename from cinelerra-5.1/thirdparty/src/ffmpeg-4.0.tar.xz rename to cinelerra-5.1/thirdparty/src/ffmpeg-4.1.tar.xz index 38e95dc0..9ce41056 100644 Binary files a/cinelerra-5.1/thirdparty/src/ffmpeg-4.0.tar.xz and b/cinelerra-5.1/thirdparty/src/ffmpeg-4.1.tar.xz differ diff --git a/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch3 b/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch3 index 3d64695a..6e2ebbcd 100644 --- a/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch3 +++ b/cinelerra-5.1/thirdparty/src/ffmpeg.git.patch3 @@ -1,6 +1,6 @@ diff -urN a/libavformat/avformat.h b/libavformat/avformat.h ---- a/libavformat/avformat.h 2018-04-20 04:02:57.000000000 -0600 -+++ b/libavformat/avformat.h 2018-04-24 11:02:20.777232001 -0600 +--- a/libavformat/avformat.h 2018-11-05 16:22:26.000000000 -0700 ++++ b/libavformat/avformat.h 2018-11-08 07:25:17.066799941 -0700 @@ -487,6 +487,9 @@ The user or muxer can override this through AVFormatContext.avoid_negative_ts @@ -22,8 +22,8 @@ diff -urN a/libavformat/avformat.h b/libavformat/avformat.h int flags; diff -urN a/libavformat/dv.c b/libavformat/dv.c ---- a/libavformat/dv.c 2018-04-13 17:34:28.000000000 -0600 -+++ b/libavformat/dv.c 2018-04-24 11:02:20.778232001 -0600 +--- a/libavformat/dv.c 2018-11-01 12:34:26.000000000 -0600 ++++ b/libavformat/dv.c 2018-11-08 07:25:17.066799941 -0700 @@ -632,6 +632,7 @@ AVInputFormat ff_dv_demuxer = { .name = "dv", @@ -33,9 +33,9 @@ diff -urN a/libavformat/dv.c b/libavformat/dv.c .read_probe = dv_probe, .read_header = dv_read_header, diff -urN a/libavformat/matroskadec.c b/libavformat/matroskadec.c ---- a/libavformat/matroskadec.c 2018-04-20 04:02:57.000000000 -0600 -+++ b/libavformat/matroskadec.c 2018-04-24 11:02:20.779232001 -0600 -@@ -4026,6 +4026,7 @@ +--- a/libavformat/matroskadec.c 2018-11-05 16:22:26.000000000 -0700 ++++ b/libavformat/matroskadec.c 2018-11-08 07:25:17.067799930 -0700 +@@ -4030,6 +4030,7 @@ AVInputFormat ff_matroska_demuxer = { .name = "matroska,webm", .long_name = NULL_IF_CONFIG_SMALL("Matroska / WebM"), @@ -43,7 +43,7 @@ diff -urN a/libavformat/matroskadec.c b/libavformat/matroskadec.c .extensions = "mkv,mk3d,mka,mks", .priv_data_size = sizeof(MatroskaDemuxContext), .read_probe = matroska_probe, -@@ -4039,6 +4040,7 @@ +@@ -4043,6 +4044,7 @@ AVInputFormat ff_webm_dash_manifest_demuxer = { .name = "webm_dash_manifest", .long_name = NULL_IF_CONFIG_SMALL("WebM DASH Manifest"), @@ -52,9 +52,9 @@ diff -urN a/libavformat/matroskadec.c b/libavformat/matroskadec.c .read_header = webm_dash_manifest_read_header, .read_packet = webm_dash_manifest_read_packet, diff -urN a/libavformat/utils.c b/libavformat/utils.c ---- a/libavformat/utils.c 2018-04-20 04:02:58.000000000 -0600 -+++ b/libavformat/utils.c 2018-04-24 11:02:20.780232001 -0600 -@@ -2471,6 +2471,13 @@ +--- a/libavformat/utils.c 2018-11-05 16:22:26.000000000 -0700 ++++ b/libavformat/utils.c 2018-11-08 07:25:17.069799908 -0700 +@@ -2472,6 +2472,13 @@ return seek_frame_byte(s, stream_index, timestamp, flags); }