#include #include #include #include #include #include #include #include using namespace std; class ANIM{ string label; string command; int steps; int interval; // Combien de temps entre chaques mouvements public: int todo(int current_time) const; void execstep() const; ANIM(PARAM_STRING _label, PARAM_STRING _cmd, int _steps, int _interval) :label(_label.ptr), command(_cmd.ptr), steps(_steps), interval(_interval) {} }; static const char *bofs_path = "/usr/bin/bofs"; static const char *docname = nullptr; static void bofs_cmd (PARAM_STRING step) { printf ("%s documents --noscripts --playstep --docname %s --step \"%s\"\n",bofs_path,docname,step.ptr); } static void bofs_cmds (vector steps) { string line = string_f ("%s documents --noscripts --playstep --docname %s",bofs_path,docname); for (auto &s:steps){ line += string_f(" --step \"%s\"",s.c_str()); } printf ("%s\n",line.c_str()); } static void bofs_sel_cmd (PARAM_STRING label, PARAM_STRING step) { printf ("%s documents --noscripts --playstep --docname %s --step \"labelselect=%s 0\" --step \"%s\" --step=\"resetselect=3\"\n",bofs_path,docname,label.ptr,step.ptr); } void labelselect(PARAM_STRING label, int seltype) { bofs_cmd(string_f("labelselect=%s %d",label.ptr,seltype)); } void settext(PARAM_STRING label, PARAM_STRING txt) { bofs_cmd(string_f("settext=%s '%s'",label.ptr,txt.ptr)); } void resetsel() { bofs_cmd("resetselect=3"); } string convert_message(PARAM_STRING message) { if (message.ptr[0] == '-' && message.ptr[1] == 'F'){ return string_f("-F %s",message.ptr+2); }else{ return string_f("-C '%s'",message.ptr); } } void bofs_send2group(PARAM_STRING from_user, PARAM_STRING groupname, PARAM_STRING groupowner, PARAM_STRING message) { printf("bofs -u %s msgs -t --groupname %s --groupowner %s %s\n" ,from_user.ptr,groupname.ptr,groupowner.ptr,convert_message(message).c_str()); } void bofs_send2inbox(PARAM_STRING from_user, std::vector recipients, PARAM_STRING message) { string recs; for (auto &r:recipients){ recs += " -D " + r; } printf("bofs -u %s msgs -t --groupname inbox %s %s\n" ,from_user.ptr,recs.c_str(),convert_message(message).c_str()); } /* Exécute une étape de l'animation */ void ANIM::execstep() const { bofs_sel_cmd(label,command); } /* Verifie si une commande doit etre executee. Retourne -1 si l'animation est complete, 0 si on est au milieu d' interval ou 1 si on doit executer une etape (envoie d'une commande a bolixo) */ int ANIM::todo(int current_time) const { int ret = -1; if (current_time < steps * interval){ if (current_time % interval == 0){ ret = 1; }else{ ret = 0; } } return ret; } ANIM anim_move (const char *label, int stepx, int stepy, int steps, int interval) { return ANIM (label,string_f("mousemove=%d,%d,false,false",stepx,stepy),steps,interval); } enum GROW_TYPE { GROW_XY,GROW_X,GROW_Y}; // steps représente le nombre d'étape à exécuter. // interval représente le temps entre chaque mouvement: 1 = 0.05 seconde, 2=0.10 seconde ANIM anim_grow (const char *label, int size, GROW_TYPE type, int steps, int interval) { const char *shiftkey="false"; const char *controlkey="false"; if (type == GROW_Y){ shiftkey="true"; }else if (type == GROW_X){ controlkey="true"; } return ANIM (label,string_f("wheel=%d,%s,%s",size,shiftkey,controlkey),steps,interval); } void scenario_run (const vector &anims) { int current_time = 0; double sleep_time = 0; while (true){ bool still_one = false; // Au moins une animation incomplete debug_printf ("current_type=%d\n",current_time); for (auto &a: anims){ int action = a.todo(current_time); if (action != -1){ still_one = true; if (action == 1){ if (sleep_time > 0) printf ("sleep %5.2lf\n",sleep_time); sleep_time = 0; a.execstep(); } } } if (!still_one) break; current_time++; sleep_time += 0.05; } } enum ELM_TYPE{ ELM_ELLIPSE, ELM_RECT, ELM_LINE, ELM_TEXT }; const unsigned DIAPO_TITLE_Y=40; const unsigned DIAPO_START=120; const unsigned DIAPO_STEP=80; const unsigned DIAPO_SUBSTEP=60; static unsigned diapo_y = DIAPO_START; static bool last_bullet = true; // Le dernier bullet était un addbullet, pas un subbullet static unsigned bullet_num=0; void resetdocument() { bofs_cmds ({"resetgame=","textsize=25"}); diapo_y = DIAPO_START; last_bullet = true; } struct COOR{ int x=0; int y=0; COOR(int _x, int _y):x(_x),y(_y){} COOR(const COOR &c):x(c.x),y(c.y){} COOR(){} COOR move (int movex, int movey){ COOR ret = *this; ret.x += movex; ret.y += movey; return ret; } }; struct SIZE{ int width=0; int height=0; SIZE(int _width, int _height):width(_width),height(_height){} }; static vector elms; // Elements de type ELLIPSE ou RECT ajoutés par addelm // la fonction delete_elms utilise ce tableau pour tout effacer void addelm (PARAM_STRING label, PARAM_STRING caption, ELM_TYPE type, COOR c, SIZE s) { static const char *tbtype[]={"ellipse","rect","line","text"}; if (is_any_of(type,ELM_ELLIPSE,ELM_RECT)) elms.push_back(label.ptr); bofs_cmd (string_f("addelm=%s \\\"%s\\\" %s %d %d %d %d" ,label.ptr,caption.ptr,tbtype[type],c.x,c.y,s.width,s.height)); resetsel(); } void addtext (PARAM_STRING label, PARAM_STRING caption, int x, int y) { addelm (label,caption,ELM_TEXT,{x,y},{1,1}); } static string escape_quote(PARAM_STRING txt) { return txt.ptr; #if 0 return copystring(txt,[](auto &c, auto pt){ if (*pt == '\'') c.replace(1,' '); }); #endif } void bullettype(PARAM_STRING label, int type) { bofs_cmd(string_f("bullettype=%s %d",label.ptr,type)); } // Cache le 'bullet' précédant le dernier point void hidelastbullet() { bullettype(string_f("bul%u",bullet_num),3); } const int TITLE_X = 600; const int BULLET_X = 300; const int SUB_BULLET_X = 350; void addtitle(PARAM_STRING txt) { addtext("title",escape_quote(txt),TITLE_X,DIAPO_TITLE_Y); bullettype("title",3); } void settabul(bool on) { if (on){ printf ("TABUL=' '\n"); }else{ printf ("TABUL=\n"); } } void addbullet(PARAM_STRING txt) { bullet_num++; addtext(string_f("bul%u",bullet_num),escape_quote(txt),BULLET_X,diapo_y); last_bullet = true; diapo_y += DIAPO_STEP; } void addsubbullet(PARAM_STRING txt) { // Si le bullet précédant était un bullet plutôt qu'un subbullet // on remonte un petit peu pour réduire la distance if (last_bullet) diapo_y = diapo_y - DIAPO_STEP + DIAPO_SUBSTEP; addtext("sub",escape_quote(txt),SUB_BULLET_X,diapo_y); last_bullet = false; diapo_y += DIAPO_SUBSTEP; } // Efface un élément void delete_elm(PARAM_STRING label) { bofs_cmd (string_f("labeldelete=%s",label.ptr)); } // Efface tous les éléments ELLIPSE et RECT ajoutés par addelm() void delete_elms() { for (auto &e:elms) delete_elm(e); elms.clear(); } void connect (const char *label1, const char *label2, int linetype) { resetsel(); labelselect(label1,1); labelselect(label2,0); bofs_cmd (string_f("selectline=%d",linetype)); resetsel(); } void assignimg (const char *label, const char *img) { labelselect (label,0); bofs_cmd (string_f("image=url:%s",img)); resetsel(); } void boxtype (const char *label, int type) { bofs_cmd (string_f("boxtype=%s %d",label,type)); } void textsize (unsigned size) { bofs_cmd (string_f("textsize=%u",size)); } void settextsize (PARAM_STRING label, int size) { bofs_cmd (string_f("settextsize=%s %d",label.ptr,size)); } void settextpos (PARAM_STRING label, int pos) { bofs_cmd (string_f("textpos=%s %d",label.ptr,pos)); } static const char *incldir = ""; void seq_pause() { printf ("%s/scn_pause || exit 1\n",incldir); } // Attend que l'utilisateur appuie sur ALT-A void waitevent() { printf ("%s/waitevent.sh pipe\n",incldir); } enum DESKTOP_NUM{ DESKTOP_SCRIPT, DESKTOP_UI }; // Affiche le desktop X dans KDE void show_desktop(DESKTOP_NUM num) { int desk = 8; if (num == DESKTOP_SCRIPT) desk = 4; printf ("qdbus org.kde.KWin /KWin setCurrentDesktop %d\n",desk); } static bool disable_obs = false; enum SCENE{ SCENE_WEBCAM, SCENE_BOLIXO_WEBCAM, SCENE_TABLEAU, SCENE_BOLIXO_UI, SCENE_WEBCAM_LOGO_TEXTE }; void obs_scene (SCENE scene, bool wait=true) { static const char *tb[]={ "scene webcam", "scene bolixo webcam", "scene tableau", "scene bolixo ui", "scene webcam logo texte" }; const char *scene_str = tb[scene]; bool bolixo_ui = strstr(scene_str,"bolixo ui")!=nullptr; if (bolixo_ui){ // On avertit que le changement va se faire dans 5 secondes printf ("echo; echo; echo \"Changement d'écran dans 5 secondes\"; echo; echo\n"); //printf ("sleep 5\n"); show_desktop(DESKTOP_UI); } if (!disable_obs) printf ("obs-cli scene switch \"%s\" || exit 1\n",scene_str); if (strstr(scene_str,"webcam")!=nullptr){ printf ("THEME=\"`tput blink`%s`tput sgr0`\"\n",tb[scene]); }else{ printf ("THEME='%s'\n",tb[scene]); } if (bolixo_ui){ //printf ("%s/waitevent.sh %s\n",incldir,docname); if (wait){ waitevent(); show_desktop(DESKTOP_SCRIPT); } } } void obs_record_start () { if (!disable_obs) printf ("obs-cli record start || exit 1\n"); } void obs_record_stop () { if (!disable_obs) printf ("obs-cli record stop || exit 1\n"); } void telescript (const char *intro, const char *texte) { // Produit une fonction bash appelé telescript(). // Cette fonction reçoit un numéro d'étape // Elle affiche le contenu mais interprète les ## comme un changement d'etape printf ("telescript(){\n"); printf ("bold=`tput smso` offbold=`tput rmso`\n"); printf ("\ttput clear\n"); printf ("\techo \"%s\"\n",intro); printf ("echo\n"); auto tb = str_cnv2lines(texte); printf ("\tetape=0\n"); for (auto &s:tb){ if (s == "##"){ printf ("\tif [ \"$etape\" = \"$1\" ]; then\n"); printf ("\t\techo $bold'---->' $THEME $offbold\n"); printf ("\telse\n"); printf ("\t\techo\n"); printf ("\tfi\n"); printf ("\tetape=`expr $etape + 1`\n"); }else{ printf ("echo \"%s\"\n\n",s.c_str()); } } printf ("}\n"); } void affiche_etape(int etape) { printf ("telescript %d\n",etape); seq_pause(); } /* Retourne la coordonnée d'un élément placé sur un cercle composé de nbelm éléments. */ COOR cercle(int nbelm, int noelm, COOR centre, int rayon) { double angle = -3*M_PI_4+M_PI*2/nbelm*noelm; COOR ret(centre); ret.x += cos(angle)*rayon; ret.y += sin(angle)*rayon; return ret; } /* Retourne la coordonnée d'un élément placé dans un tableau composé de nbx X nby éléments. */ COOR tableau(int x, int y, COOR centre, int distance) { COOR ret(centre); ret.x += x*distance; ret.y += y*distance; return ret; }