/*'sexy.c': "SEXY(Splendid and Enormous XY-protter)" (G.robot 2004) | 起動 program. | 他に header file 'sexy.h'が必要で、試運転用にtest_drive.cを作った。 | さらに、コンパイルを助ける'makefile'を用意した。 |※更新履歴※ | 5/ 8/2004 Taka: マウスで描いた図のdataを取り出すprogramを作成 | 5/12/2004 Taka: dataをwindow上にprotするroutineを作成 | 5/13/2004 Taka: data save/load機能を追加 | 5/22/2004 Taka: 使いやすく手直し | 5/24/2004 Taka: Undoの機能を追加 | 5/25/2004 Taka: re-edit機能追加, data fileにcoment(先頭文字'#') | 5/27/2004 Maru: printer port に信号を送るprocess作成 | 5/31/2004 Taka: protのための信号を回路に送るprocess完成 | 6/15/2004 Taka: mouse button の対応表示部作成 | 6/24/2004 Taka: protの信号を変更, 進行状況表示機能追加 | 6/25/2004 Taka: 押されたbuttonを光らせるのと直線エコーの問題解決 | 7/ 1/2004 Taka: ソレノイドコイルの遅れを待つようにした | 7/ 2/2004 Taka: 零点補正(未定)のためのセンサとの通信部作成 | 7/ 2/2004 Taka: 回路にあわせて信号を変更(yの向きを逆に) | 7/ 6/2004 Taka: 他の意見をもとに使い勝手を改善 | 7/10/2004 Taka: Dr田中の真似をして実行時のoption機能付加 | 7/14/2004 Taka: 今これを読んでる貴方のために説明を付加 | 7/25/2004 Taka: 再描画にPixmapを用いてみたが、重くなったのでやめた | 7/29/2004 Taka: 以前より見やすく使いやすくなった最終版完成 */ #include "sexy.h" main(int a_c,char *a_v[]) { Window root,hlp; GC gc[2]; //0:XOR 1:bold XSetWindowAttributes att; XEvent evt; //何が起こったか(マウス操作など)を感知 char name[80]; int i=0/*最後まで一時変数としてひっぱりだこ*/, loaded=0/*loadされたかどうかを調べる*/, but/*マウスボタン*/,flg=DoRed|DoGreen|DoBlue/*3原色全て操作*/; Bool contig=False/*始点がsetされたか調べる*/,edited=False; double pred,real,error; //この3つは時間誤差を計算するために用意した Colormap cm; unsigned long pln[1],pix[7]; //自分で定義する色 XColor bg; //名前を知らない色を定義するときに必要 COORD data[MAX],rub={0,0,OFF}; //座標 // --------------------------------- 初期設定(L146まで) // judgement of options while(--a_c){ //last to L89 if((*++a_v)[0]=='-') switch(i=*++a_v[0]){ //'-'のときその次の字によって分岐 /* (++x)[0]は「(++x)の[0]」で、++x[0]は++(x[0])つまり 「(x[0])を++」っつーこと。*/ case 'f': case 'p': break; //fかpならbreak default: //間違えたか、 printf("Wrong option. \a"); case 'h': //hのときは、 printf("You can use these below.\n\t-c: Display coments.\n\t-f: Disignate filename. Don't forget '.sxy' in tail.\n\t-h: Display this help.\n\t-p: Disignate PPS. Input integer.\n\nIf there're too many arguments, last one'll be picked.\n"); exit(0); //ヘルプを書いて終了 case 'c': Coments(); //製作後記(?)を表示 } //end of switch in L65 else switch(i){ //1文字目が'-'でないとき(値とみなす)、iは前のままだから case 'f': loaded=load(data,*a_v); break; case 'p': sscanf(*a_v,"%d",&pps); //数字に変換して代入 break; default: printf("Illegal option was ignored.\n"); } //end of switch in L80 } //end of while in L63 dis=XOpenDisplay(NULL); root=RootWindow(dis,0); //same as DefaultRootWindow cm=DefaultColormap(dis,0); if(XAllocColorCells(dis,cm,False,pln,1,pix,7)){ //色を定義 XStoreNamedColor(dis,cm,"black",pix[0],flg); XStoreNamedColor(dis,cm,"white",pix[6],flg); for(i=1;i<=3;i++) XStoreNamedColor(dis,cm,"LightGrey",pix[i],flg); //buttonの色 XStoreNamedColor(dis,cm,"MediumPurple",pix[4],flg); bg.pixel=pix[5]; //NamedColor以外の色も bg.flags=flg; //使いたいときのために bg.red=52992l; //この方法がある。 bg.green=48896l; //つまり、 bg.blue=32768l; //XStoreNamedColorと XStoreColor(dis,cm,&bg); //同じ役割なんやよ。 //下地が何色でも、plane mask時は水色で表示 XStoreNamedColor(dis,cm,"LightSkyBlue",pix[0]|pln[0],flg); XStoreNamedColor(dis,cm,"LightSkyBlue",pix[4]|pln[0],flg); XStoreNamedColor(dis,cm,"LightSkyBlue",pix[6]|pln[0],flg); } //end of if(Alloc) in L95 else{ printf("Allocating error.\n"); exit(0); } canv=XCreateSimpleWindow(dis,root,400,100,CAN_W,CAN_H,2,pix[0],pix[6]); hlp=XCreateSimpleWindow(dis,root,0,0,160,240,2,pix[0],pix[5]); XSelectInput(dis,canv,ExposureMask|ButtonPressMask|PointerMotionMask); XSelectInput(dis,hlp,ExposureMask); XStoreName(dis,canv,"canvas - SEXY"); //windowのtitle設定 XStoreName(dis,hlp,"mouse buttons"); XWarpPointer(dis,None,root,0,0,0,0,0,R_H-CAN_H); //pointerを強制移動。arg2,4-7は諸条件今回は無関係なので0にした XMapWindow(dis,canv); do{ XNextEvent(dis,&evt); }while(evt.type!=Expose); //表示されるまで待つ att.backing_store=WhenMapped; //これは機能しないことが多いので、expose event XChangeWindowAttributes(dis,canv,CWBackingStore,&att); //も併用する(後述) XChangeWindowAttributes(dis,hlp,CWBackingStore,&att); //GC(筆)を2本用意 for(i=0;i<2;i++) gc[i]=XCreateGC(dis,root,0,0); XSetForeground(dis,gc[1],pix[0]); XSetLineAttributes(dis,gc[1],3,LineSolid,CapRound,JoinRound); //幅:3,端:丸く XSetFunction(dis,gc[0],GXxor/*XOR演算*/); //色の演算法.他方はGXcopy(上書き) // ------------------------------------- ここからがmain do{ //last to L296 XDefineCursor(dis,canv,XCreateFontCursor(dis,XC_cross)); //crusorを十字に data[0].x=0; data[0].y=0; data[0].connection=OFF; while(!loaded&&i!='e'&&ask("Do you want to load a data file?([Y]/[N])")=='y') loaded=load(data,filename(name,"load")); loaded*=(loaded!=ERR); //ERRのときは0に num=loaded; if(loaded&&i!='e'){ trace(gc[1],data,0,num); if(num>MAX-2||ask("Do you want to edit?([Y]/[N])")!='y') goto PROCESS; } //end of if(loaded) printf("\n OK, now draw your cool image!\n"); XMoveWindow(dis,canv,0,R_H-CAN_H); //canvas windowを最上面へ XMapWindow(dis,hlp); XMoveWindow(dis,hlp,780,0); //help windowを移動 // --------------------------------- お絵書き(L252まで) i='n'; //roop条件のための初期化 do{ //last to L252 lest(num); XNextEvent(dis,&evt); //イベントを調べる(XFlushの役割も持つ) switch(evt.type){ //to L251 case Expose: //一旦隠れた部分が露出したら再描画 if(evt.xany.window==canv) //XAny構造体は全XEvent共用体で共通な要素を持つ trace(gc[1],data,0,num); if(evt.xany.window==hlp) mouse(root,hlp,cm,pix); continue; case MotionNotify: //マウスが動いたとき(L192まで) if(contig){ //始点が指定されてたらラバーバンドを表示 XSetPlaneMask(dis,gc[0],pln[0]); //plane0 のみに描画 XSetForeground(dis,gc[0],0xffffffff); //全色bit有効 if(rub.connection==ON) //以前の線を消す XDrawLine(dis,canv,gc[0],re_x(data[num].x),re_y(data[num].y),rub.x,rub.y); rub.x=evt.xmotion.x; rub.y=evt.xmotion.y; //新しい線を引く XDrawLine(dis,canv,gc[0],re_x(data[num].x),re_y(data[num].y),rub.x,rub.y); rub.connection=ON; //ラバーバンド判別のため } default: continue; //'case MotionNotify'の後わりも兼ねる case ButtonPress: //ボタンが押されたら(L246まで) if(contig){ //始点が指定されてたときは補助線・点を消す if(rub.connection==ON){ //ラバーバンドを消す XDrawLine(dis,canv,gc[0],re_x(data[num].x),re_y(data[num].y),rub.x,rub.y); XSetPlaneMask(dis,gc[0],0xffffffff); //全plane使用(L191のmaskを解除) rub.connection=OFF; //ラバーバンド判定のため } mark(gc[0],re_x(data[num].x),re_y(data[num].y),pix); //●を消す } encolor(cm,pix[evt.xbutton.button],flg); switch(evt.xbutton.button){ //さらにどのボタンかで分岐 case 1: //左クリック(set) edited=True; num++; data[num].x=evt.xbutton.x/CELL; data[num].y=evt.xbutton.y/CELL; if(contig){ //始点が指定されていたら線分が描かれる data[num-1].connection=ON; trace(gc[1],data,num-1,num); } mark(gc[0],re_x(data[num].x),re_y(data[num].y),pix); contig=True; //始点が設定されたことを覚えておくため break; case 2: //中クリック(undo) if(!num) continue; //num=0のとき無視 contig=True; if(num>1){ edited=True; if(data[num].connection==ON){ XClearWindow(dis,canv); trace(gc[1],data,0,--num); } else data[num].connection=ON; mark(gc[0],re_x(data[num].x),re_y(data[num].y),pix); //●を描くか消す break; } case 3: //右クリック(cancel) if(contig){ //始点が設定されてて、 if(data[num-1].connection==OFF) num--; //その始点が直前の線分の終点でなければ始点を取消 else data[num].connection=OFF; //…であるなら連続をやめる contig=False; //いずれも始点はunsetとなる } else i=ask("\nAre you sure to end drawing?([Y]/[N])"); //ここで訊いといて、L242で止めるかどうか判断 } //end of switch(button) in L212 break; } //end of switch(type) in L179 }while(i=='n'&&num400){ //ppsが不適当なら訊く printf("The current PPS is inappropreate. Input PPS: "); fpurge(stdin); scanf("%d",&pps); } //end of while in L281 printf("PPS=%d\n",pps); do{ //last to L293 XSetInputFocus(dis,None,RevertToNone/*ここは何でも良い*/,CurrentTime/*今やる*/); //keyboard入力を受け付けない XFlush(dis); if((real=draw(data,num))==ERR) exit(0); printf("(p-r=%.1lfsec,p/r=%6.6lf)\n",pred-real,pred/(double)real); XSetInputFocus(dis,PointerRoot,RevertToParent/*unmapてたらその親windowへ*/,CurrentTime); //forcusしなおす }while(ask("Do you want to prot again?([Y]/[N])")!='n'); } //end of if(ask) in L280 } //end of if(num) in L260 switch(i=ask("What next do you like to do?([Q]uit/[E]dit this/[O]pen new)")){ case 'o': XClearWindow(dis,canv); loaded=num=0; edited=False; break; case 'e': edited=True; break; default: //case 'q'含む i='q'; //たくさんネストしてるので、終るにはbreak以外の方法を取らざるを得ない } //end of switch in L297 }while(i!='q'); //end of do in L149(最初に戻る) printf("Ending...\n"); XDestroyWindow(dis,canv); XDestroyWindow(dis,hlp); XCloseDisplay(dis); return 0; //←正常終了の証なのでつけた方が親切らしい }