InputWindow.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018
  1. #include "lib/ballistics/ballistics.h"
  2. #include "InputWindow.h"
  3. InputWindow::InputWindow(int w, int h, const char* title):Fl_Window(w,h,title){
  4. // Solution pointers. Must be initialized to NULL so we don't accidentally try to free them later.
  5. gsln=NULL;
  6. mem1=NULL;
  7. mem2=NULL;
  8. mem3=NULL;
  9. mem4=NULL;
  10. mem5=NULL;
  11. mem6=NULL;
  12. mem7=NULL;
  13. mem8=NULL;
  14. // A (double*) pointer to the actual solution data. Initialize to
  15. // Null so we can make sure to free any memory it has after a solution
  16. // is closed.
  17. Solution=NULL;
  18. Smem1=NULL;
  19. Smem2=NULL;
  20. Smem3=NULL;
  21. Smem4=NULL;
  22. Smem5=NULL;
  23. Smem6=NULL;
  24. Smem7=NULL;
  25. Smem8=NULL;
  26. // Start drawing the widgets on screen.
  27. begin();
  28. // Draw any general purpose borders or labels.
  29. Fl_Box* GBox = new Fl_Box(250,80,140,95,"Drag Function");
  30. GBox->box(FL_BORDER_BOX);
  31. GBox->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE);
  32. // Create and place the Drag Function inputs on the form.
  33. inG1 = new Fl_Round_Button(270,105,30,15,"G1");
  34. inG2 = new Fl_Round_Button(270,125,30,15,"G2");
  35. inG5 = new Fl_Round_Button(270,145,30,15,"G5");
  36. inG6 = new Fl_Round_Button(330,105,30,15,"G6");
  37. inG7 = new Fl_Round_Button(330,125,30,15,"G7");
  38. inG8 = new Fl_Round_Button(330,145,30,15,"G8");
  39. inG1->type(FL_RADIO_BUTTON);
  40. inG2->type(FL_RADIO_BUTTON);
  41. inG5->type(FL_RADIO_BUTTON);
  42. inG6->type(FL_RADIO_BUTTON);
  43. inG7->type(FL_RADIO_BUTTON);
  44. inG8->type(FL_RADIO_BUTTON);
  45. inG1->set();
  46. // Create and place the input fields on the form.
  47. inName = new Fl_Input(55,45,335,20,"Name ");
  48. inBC = new Fl_Float_Input(10,80,50,20," Drag Coefficient");
  49. inWeight=new Fl_Int_Input(10,105,50,20," Projectile Weight (grains)");
  50. inMV = new Fl_Int_Input(10,130,50,20," Initial Velocity (ft/s)");
  51. inZero = new Fl_Int_Input(10,155,50,20," Zero Range (yds)");
  52. inSH = new Fl_Float_Input(10,180,50,20," Sight Height Over Bore (in)");
  53. inAngle = new Fl_Int_Input(10,205,50,20," Shooting Angle (deg)");
  54. inVwind = new Fl_Int_Input(10,230,50,20," Wind Velocity (mi/hr)");
  55. inAwind = new Fl_Int_Input(10,255,50,20," Wind Angle (0-360 deg)");
  56. inName->align(FL_ALIGN_LEFT);
  57. inBC->align(FL_ALIGN_RIGHT);
  58. inWeight->align(FL_ALIGN_RIGHT);
  59. inMV->align(FL_ALIGN_RIGHT);
  60. inZero->align(FL_ALIGN_RIGHT);
  61. inAngle->align(FL_ALIGN_RIGHT);
  62. inVwind->align(FL_ALIGN_RIGHT);
  63. inAwind->align(FL_ALIGN_RIGHT);
  64. inSH->align(FL_ALIGN_RIGHT);
  65. inName->value("308 Win Match, 168gr Sierra Match King");
  66. inBC->value("0.465");
  67. inWeight->value("168");
  68. inMV->value("2650");
  69. inZero->value("200");
  70. inAngle->value("0");
  71. inVwind->value("0");
  72. inAwind->value("0");
  73. inSH->value("1.6");
  74. // Put a checkbox to enable or disable atmospheric corrections.
  75. ckWeather = new Fl_Check_Button(10,290,20,20,"Enable Atmospheric Corrections");
  76. ckWeather->align(FL_ALIGN_RIGHT);
  77. ckWeather->callback(cb_ckWeather,this);
  78. // Now the atmospheric inputs.
  79. inAltitude = new Fl_Int_Input(10,315,50,20," Altitude (ft)");
  80. inTemp = new Fl_Int_Input(10,340,50,20," Temperature (F)");
  81. inPressure = new Fl_Float_Input(10,365,50,20," Barometric Pressure (in Hg)");
  82. inHumidity = new Fl_Int_Input(10,390,50,20," Relative Humidity (%)");
  83. inTemp->align(FL_ALIGN_RIGHT);
  84. inPressure->align(FL_ALIGN_RIGHT);
  85. inAltitude->align(FL_ALIGN_RIGHT);
  86. inHumidity->align(FL_ALIGN_RIGHT);
  87. // Set the default to standard atmosphere.
  88. inTemp->value("59");
  89. inAltitude->value("0");
  90. inPressure->value("29.53");
  91. inHumidity->value("78");
  92. // Disable the atmospheric conditions at first since many users may not want to use it.
  93. ckWeather->activate();
  94. inTemp->deactivate();
  95. inAltitude->deactivate();
  96. inPressure->deactivate();
  97. inHumidity->deactivate();
  98. // Initialize the output window display.
  99. oStatus = new Fl_Multiline_Output(10,420,380,70,"Solution Status");
  100. oStatus->align(FL_ALIGN_LEFT | FL_ALIGN_TOP | FL_ALIGN_INSIDE);
  101. oStatus->value("GNU Ballistic Computer: Waiting for input.");
  102. // Create and place buttons on the form.
  103. btSolve = new Fl_Button( 280, 380, 50, 30, "So&lve");
  104. btReset = new Fl_Button( 340, 380, 50, 30, "&Reset");
  105. btSolve->callback(cb_Solve,this);
  106. btReset->callback(cb_Clear, this);
  107. // Declare the menu bar variables
  108. // m for menu, mc for menu choice.
  109. menu = new Fl_Menu_Bar(0,0,400,30, "MENU");
  110. Fl_Menu_Item m_File = {"&File",0,0,0,FL_SUBMENU};
  111. Fl_Menu_Item mc_New = {"&New...",0,(Fl_Callback*)cb_mNew,this};
  112. Fl_Menu_Item mc_Open = {"&Open...",0,(Fl_Callback*)cb_Open,this};
  113. Fl_Menu_Item mc_Save = {"&Save...",0,(Fl_Callback*)cb_Save,this};
  114. Fl_Menu_Item mc_AdvExport = {"E&xport Data..",0,(Fl_Callback*)cb_Nothing,this};
  115. Fl_Menu_Item mc_Quit = {"&Quit",0,(Fl_Callback*)cb_Quit,this};
  116. Fl_Menu_Item m_Analysis = {"&Analysis",0,0,0, FL_SUBMENU};
  117. Fl_Menu_Item mc_RangeTable = {"&Range Table",0,(Fl_Callback*)cb_RangeTable,this};
  118. Fl_Menu_Item mc_QuickPlot = {"Quick &Plot",0,(Fl_Callback*)cb_Plot, this};
  119. Fl_Menu_Item mc_RangeCard = {"&Range Card",0,(Fl_Callback*)cb_Nothing};
  120. Fl_Menu_Item mc_ClickChart = {"&Click Chart",0,(Fl_Callback*)cb_Nothing,this,FL_MENU_DIVIDER};
  121. Fl_Menu_Item mc_MVA = {"&Advanced Analysis",0,(Fl_Callback*)cb_Nothing,this};
  122. Fl_Menu_Item m_Tools = {"&Tools",0,0,0, FL_SUBMENU};
  123. Fl_Menu_Item mc_OptimizePBR = {"&Optimize PBR",0,(Fl_Callback*)cb_PBR,this};
  124. Fl_Menu_Item mc_CalcBC = {"&Calculate Drag Coefficient",0,(Fl_Callback*)cb_Nothing,this,FL_MENU_DIVIDER};
  125. Fl_Menu_Item mc_Options = {"&Options",0,(Fl_Callback*)cb_Options,this};
  126. Fl_Menu_Item m_Storage = {"&Solution Memory",0,0,0, FL_SUBMENU};
  127. Fl_Menu_Item mc_Store1 = {"Store to Memory 1 ",0,(Fl_Callback*)cb_Store1,this};
  128. Fl_Menu_Item mc_Store2 = {"Store to Memory 2 ",0,(Fl_Callback*)cb_Store2,this,FL_MENU_DIVIDER};
  129. Fl_Menu_Item mc_Store3 = {"Store to Memory 3 ",0,(Fl_Callback*)cb_Store3,this};
  130. Fl_Menu_Item mc_Store4 = {"Store to Memory 4 ",0,(Fl_Callback*)cb_Store4,this};
  131. Fl_Menu_Item mc_Store5 = {"Store to Memory 5 ",0,(Fl_Callback*)cb_Store5,this};
  132. Fl_Menu_Item mc_Store6 = {"Store to Memory 6 ",0,(Fl_Callback*)cb_Store6,this};
  133. Fl_Menu_Item mc_Store7 = {"Store to Memory 7 ",0,(Fl_Callback*)cb_Store7,this};
  134. Fl_Menu_Item mc_Store8 = {"Store to Memory 8 ",0,(Fl_Callback*)cb_Store8,this};
  135. Fl_Menu_Item m_Help = {"&Help",0,0,0, FL_SUBMENU};
  136. Fl_Menu_Item mc_Help = {"&Help",0,(Fl_Callback*)cb_HelpWindow};
  137. Fl_Menu_Item mc_License = {"&License",0,(Fl_Callback*)cb_LicenseWindow};
  138. Fl_Menu_Item mc_About = {"&About",0,(Fl_Callback*)cb_AboutWindow};
  139. // Set initial condition for menu items.
  140. m_Analyze.deactivate();
  141. m_Aids.deactivate();
  142. //mc_Export.deactivate(); // Data exports from the RangeTable window.
  143. // These are planned features, but haven't been done yet.
  144. ////// TODO //////
  145. m_Storage.deactivate();
  146. mc_RangeCard.deactivate();
  147. mc_ClickChart.deactivate();
  148. mc_CalcBC.deactivate();
  149. m_Solution.deactivate();
  150. mc_MVA.deactivate();
  151. mc_AdvExport.deactivate();
  152. m_Analysis.deactivate();
  153. mc_Options.deactivate();
  154. #define MANALYSIS 7
  155. #define MSTORAGE 19
  156. Fl_Menu_Item menuitems[] = {
  157. m_File, //0
  158. mc_New,
  159. mc_Open,
  160. mc_Save,
  161. mc_AdvExport,
  162. mc_Quit,
  163. {0},//6
  164. m_Analysis, //7
  165. mc_RangeTable,
  166. mc_QuickPlot,
  167. mc_RangeCard,
  168. mc_ClickChart,
  169. mc_MVA,
  170. {0}, // 13
  171. m_Tools,
  172. mc_OptimizePBR,
  173. mc_CalcBC,
  174. mc_Options,
  175. {0},
  176. m_Storage,
  177. mc_Store1, //20
  178. mc_Store2, //21
  179. mc_Store3,
  180. mc_Store4,
  181. mc_Store5,
  182. mc_Store6,
  183. mc_Store7,
  184. mc_Store8,
  185. {0},
  186. m_Help, //23
  187. mc_Help,
  188. mc_License,
  189. mc_About,
  190. {0}, //27
  191. {0}
  192. };
  193. menu->copy(menuitems);
  194. end();
  195. show();
  196. }
  197. InputWindow::~InputWindow(){
  198. // Free any memory we are using.
  199. if (Solution!=NULL) {free(Solution);Solution=NULL;}
  200. if (Smem1!=NULL) { free(Smem1); Smem1=NULL; }
  201. if (Smem2!=NULL) { free(Smem2); Smem2=NULL; }
  202. if (Smem3!=NULL) { free(Smem3); Smem3=NULL; }
  203. if (Smem4!=NULL) { free(Smem4); Smem4=NULL; }
  204. if (Smem5!=NULL) { free(Smem5); Smem5=NULL; }
  205. if (Smem6!=NULL) { free(Smem6); Smem6=NULL; }
  206. if (Smem7!=NULL) { free(Smem7); Smem7=NULL; }
  207. if (Smem8!=NULL) { free(Smem8); Smem8=NULL; }
  208. if (gsln!=NULL) { gsln->~GBCSolution(); delete gsln; gsln=NULL;}
  209. if (mem1!=NULL) { mem1->~GBCSolution(); delete mem1; mem1=NULL;}
  210. if (mem2!=NULL) { mem2->~GBCSolution(); delete mem2; mem2=NULL;}
  211. if (mem3!=NULL) { mem3->~GBCSolution(); delete mem3; mem3=NULL;}
  212. if (mem4!=NULL) { mem4->~GBCSolution(); delete mem4; mem4=NULL;}
  213. if (mem5!=NULL) { mem5->~GBCSolution(); delete mem5; mem5=NULL;}
  214. if (mem6!=NULL) { mem6->~GBCSolution(); delete mem6; mem6=NULL;}
  215. if (mem7!=NULL) { mem7->~GBCSolution(); delete mem7; mem7=NULL;}
  216. if (mem8!=NULL) { mem8->~GBCSolution(); delete mem8; mem8=NULL;}
  217. delete inG1;
  218. delete inG2;
  219. delete inG5;
  220. delete inG6;
  221. delete inG7;
  222. delete inG8;
  223. delete inName;
  224. delete inBC;
  225. delete inWeight;
  226. delete inMV;
  227. delete inZero;
  228. delete inSH;
  229. delete inAngle;
  230. delete inVwind;
  231. delete inAwind;
  232. delete ckWeather;
  233. delete inAltitude;
  234. delete inTemp;
  235. delete inPressure;
  236. delete inHumidity;
  237. delete oStatus;
  238. delete btSolve;
  239. delete btReset;
  240. }
  241. void InputWindow::cb_ckWeather(Fl_Widget* o, void* v){
  242. InputWindow* T=(InputWindow*)v;
  243. if (T->ckWeather->value()==1){
  244. T->inTemp->activate();
  245. T->inPressure->activate();
  246. T->inAltitude->activate();
  247. T->inHumidity->activate();
  248. }
  249. else if (T->ckWeather->value()==0){
  250. T->inTemp->deactivate();
  251. T->inPressure->deactivate();
  252. T->inAltitude->deactivate();
  253. T->inHumidity->deactivate();
  254. }
  255. }
  256. void InputWindow::cb_Solve(Fl_Widget* o, void* vd) {
  257. // If we have an old solution, clean up its memory areas now.
  258. // Disable the analysis menu.
  259. DisableMenu(vd);
  260. InputWindow* T = (InputWindow*)vd;
  261. // Make some local pointers to use in the function, before we assign the solution
  262. // to the currently selected "working" solution on the UI.
  263. GBCSolution* lsln = NULL;
  264. double* lSolution = NULL;
  265. double bc=-1; // The ballistic coefficient for the projectile.
  266. double v=-1; // Intial velocity, in ft/s
  267. double sh=-1; // The Sight height over bore, in inches.
  268. double angle=-1; // The shooting angle (uphill / downhill), in degrees.
  269. double zero=-1; // The zero range of the rifle, in yards.
  270. double windspeed=-1; // The wind speed in miles per hour.
  271. double windangle=-1; // The wind angle (0=headwind, 90=right to left, 180=tailwind, 270/-90=left to right)
  272. int df=0;
  273. int numRows=0;
  274. char txt1[1024];
  275. double zeroangle=-1; // The bore / sight angle.
  276. bc = atof(T->inBC->value());
  277. v = atof(T->inMV->value());
  278. sh = atof(T->inSH->value());
  279. angle=atof(T->inAngle->value());
  280. zero=atof(T->inZero->value());
  281. windspeed=atof(T->inVwind->value());
  282. windangle=atof(T->inAwind->value());
  283. if (T->inG1->value()==1) df=G1;
  284. else if (T->inG2->value()==1) df=G2;
  285. else if (T->inG5->value()==1) df=G5;
  286. else if (T->inG6->value()==1) df=G6;
  287. else if (T->inG7->value()==1) df=G7;
  288. else if (T->inG8->value()==1) df=G8;
  289. // If the Enable Weather checkbox is activated, we correct the
  290. // Ballistic coefficient for the non-std weather conditions.
  291. if (T->ckWeather->value()==1){
  292. double Altitude = atof(T->inAltitude->value());
  293. double Barometer = atof(T->inPressure->value());
  294. double Temperature = atof(T->inTemp->value());
  295. double RH = atof(T->inHumidity->value())/100;
  296. bc = AtmCorrect(bc, Altitude,Barometer,Temperature,RH);
  297. }
  298. // Find the zero angle of the bore relative to the sighting system.
  299. zeroangle=ZeroAngle(df,bc,v,sh,zero,0);
  300. // Generate a solution using the GNU Ballistics library call.
  301. numRows = SolveAll(df,bc,v,sh,angle,zeroangle,windspeed,windangle,&(lSolution));
  302. // If we get a valid solution, store it as a new GBC Solution.
  303. // T->gsln was cleaned up at the beginning of this function,
  304. // so we know it points to NULL already.
  305. if (numRows>0 && lSolution!=NULL){ // Solution is valid with no errors.
  306. // Store some general data about the load and weather conditions in the 2048 extra bytes.
  307. lsln = new GBCSolution(
  308. lSolution,
  309. T->inName->value(),
  310. atof(T->inBC->value()),
  311. atof(T->inSH->value()),
  312. atoi(T->inWeight->value()),
  313. atoi(T->inMV->value()),
  314. atoi(T->inAngle->value()),
  315. atoi(T->inZero->value()),
  316. atoi(T->inVwind->value()),
  317. atoi(T->inAwind->value()),
  318. atoi(T->inTemp->value()),
  319. atoi(T->inHumidity->value()),
  320. atof(T->inPressure->value()),
  321. atoi(T->inAltitude->value()),
  322. (int)lSolution[10*__BCOMP_MAXRANGE__+1],
  323. T->ckWeather->value(),
  324. df
  325. );
  326. // Update the maximum valid range of the solution.
  327. // We do this separately because I'm too lazy to update the GBCSolution() constructor,
  328. // but we need this data to pass into the RangeWindow for maximum distances.
  329. lsln->MaxRows(numRows);
  330. if (lsln == NULL){
  331. // Inform the user of our failure.
  332. sprintf(txt1,"GNU Ballistics Computer: Solution failed! Unknown error.");
  333. T->oStatus->value(txt1);
  334. return;
  335. }
  336. // Otherwise we assume success, and inform the user of our success.
  337. sprintf(txt1,"GNU Ballistics Computer: Solution Valid.\nSolution's maximum valid range is %d yards\nUse the options in the 'Solution' menu to view results.",numRows-2);
  338. T->oStatus->value(txt1);
  339. EnableMenu((InputWindow*) vd);
  340. // Now we need to figure out which solution the user wanted to store this as, and
  341. // assign our local pointers to the user's requested solution.
  342. if (T->gsln != NULL){
  343. //if (T->gsln->sln != NULL) printf("398: T->gsln->sln = %p",T->gsln->sln); //free(T->gsln->sln);
  344. delete(T->gsln);
  345. }
  346. T->gsln=lsln;
  347. }
  348. return;
  349. }
  350. void InputWindow::EnableMenu(void* v){
  351. InputWindow* T = (InputWindow*)v;
  352. // Enable the Analyze menu. This function is a crude way to do it, but it works.
  353. // I'm looking for a better way to do this, but have yet to find one.
  354. Fl_Menu_Item* mp;
  355. mp=(Fl_Menu_Item*)&(T->menu->menu()[MANALYSIS]);
  356. mp->activate();
  357. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE]);
  358. mp->activate();
  359. T->redraw();
  360. }
  361. void InputWindow::DisableMenu(void* v){
  362. InputWindow* T = (InputWindow*)v;
  363. // Disable the Analyze menu. This function is a crude way to do it.
  364. Fl_Menu_Item* mp;
  365. mp=(Fl_Menu_Item*)&(T->menu->menu()[MANALYSIS]);
  366. mp->deactivate();
  367. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE]);
  368. mp->deactivate();
  369. T->redraw();
  370. }
  371. // While I get the program running, some buttons will
  372. // do nothing. For that they get to point to this callback.
  373. void InputWindow::cb_Nothing(Fl_Widget*, void* v) {
  374. ;
  375. }
  376. void InputWindow::cb_Quit(Fl_Widget*, void* v) {
  377. InputWindow* T = (InputWindow*)v;
  378. T->~InputWindow();
  379. }
  380. // We seem to have a memory leak here??
  381. // When the use clicks "solve" and "reset" and "solve" again, there is an extra 460 kb lost.
  382. void InputWindow::cb_Clear(Fl_Widget* o, void* v) {
  383. InputWindow* T=(InputWindow*)v;
  384. // When the "Reset" button is clicked, we want to
  385. // clear out the old solution and restore std. conditions.
  386. DisableMenu(v);
  387. T->inBC->value("0.465");
  388. T->inMV->value("2650");
  389. T->inZero->value("200");
  390. T->inAngle->value("0");
  391. T->inSH->value("1.6");
  392. T->inVwind->value("0");
  393. T->inAwind->value("0");
  394. T->inTemp->value("59");
  395. T->inWeight->value("168");
  396. T->inAltitude->value("0");
  397. T->inPressure->value("29.53");
  398. T->inHumidity->value("78");
  399. T->inName->value("308 Win Match, 168gr Sierra Match King");
  400. T->ckWeather->clear();
  401. T->cb_ckWeather(o,v);
  402. T->oStatus->value("GNU Ballistic Computer: Solution Reset");
  403. T->inG1->value(1);
  404. T->inG2->value(0);
  405. T->inG5->value(0);
  406. T->inG6->value(0);
  407. T->inG7->value(0);
  408. T->inG8->value(0);
  409. // Free up any memory we have been using.
  410. // Free any memory we are using.
  411. if (T->Solution!=NULL) {free(T->Solution); T->Solution=NULL;}
  412. if (T->Smem1!=NULL) { free(T->Smem1); T->Smem1=NULL; }
  413. if (T->Smem2!=NULL) { free(T->Smem2); T->Smem2=NULL; }
  414. if (T->Smem3!=NULL) { free(T->Smem3); T->Smem3=NULL; }
  415. if (T->Smem4!=NULL) { free(T->Smem4); T->Smem4=NULL; }
  416. if (T->Smem5!=NULL) { free(T->Smem5); T->Smem5=NULL; }
  417. if (T->Smem6!=NULL) { free(T->Smem6); T->Smem6=NULL; }
  418. if (T->Smem7!=NULL) { free(T->Smem7); T->Smem7=NULL; }
  419. if (T->Smem8!=NULL) { free(T->Smem8); T->Smem8=NULL; }
  420. if (T->gsln!=NULL) { T->gsln->~GBCSolution(); delete T->gsln; T->gsln=NULL;}
  421. if (T->mem1!=NULL) { T->mem1->~GBCSolution(); delete T->mem1; T->mem1=NULL;}
  422. if (T->mem2!=NULL) { T->mem2->~GBCSolution(); delete T->mem2; T->mem2=NULL;}
  423. if (T->mem3!=NULL) { T->mem3->~GBCSolution(); delete T->mem3; T->mem3=NULL;}
  424. if (T->mem4!=NULL) { T->mem4->~GBCSolution(); delete T->mem4; T->mem4=NULL;}
  425. if (T->mem5!=NULL) { T->mem5->~GBCSolution(); delete T->mem5; T->mem5=NULL;}
  426. if (T->mem6!=NULL) { T->mem6->~GBCSolution(); delete T->mem6; T->mem6=NULL;}
  427. if (T->mem7!=NULL) { T->mem7->~GBCSolution(); delete T->mem7; T->mem7=NULL;}
  428. if (T->mem8!=NULL) { T->mem8->~GBCSolution(); delete T->mem8; T->mem8=NULL;}
  429. // Turn the memory labels back to black to show they are null.
  430. Fl_Menu_Item* mp;
  431. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+1]); mp->labelcolor(FL_BLACK);
  432. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+2]); mp->labelcolor(FL_BLACK);
  433. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+3]); mp->labelcolor(FL_BLACK);
  434. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+4]); mp->labelcolor(FL_BLACK);
  435. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+5]); mp->labelcolor(FL_BLACK);
  436. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+6]); mp->labelcolor(FL_BLACK);
  437. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+7]); mp->labelcolor(FL_BLACK);
  438. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+8]); mp->labelcolor(FL_BLACK);
  439. }
  440. // Using the "New" Menu button does the same thing as the reset button.
  441. void InputWindow::cb_mNew(Fl_Widget* o, void* v){
  442. DisableMenu(v);
  443. InputWindow* T=(InputWindow*)v;
  444. T->cb_Clear(o,v);
  445. T->oStatus->value("GNU Ballistic Computer: Solution cleared. \nNow begin new Solution");
  446. }
  447. // Don't remember where these came from... I'm not sure they're used at all in fact.
  448. // I've commented them out for now. The next release will have them removed if no
  449. // break-downs are found due to removal. I think they are from when I first started
  450. // making the program, but didn't really know what to do yet for FLTK.
  451. //void InputWindow::cb_quit(Fl_Widget* o, void* v) {
  452. // ( (InputWindow*)v )->cb_quit_i();
  453. //}
  454. //void InputWindow::cb_quit_i() {
  455. // hide();
  456. //}
  457. //void InputWindow::cb_mOpen(Fl_Widget* o, void* v) {
  458. // DisableMenu(v);
  459. // InputWindow* T = (InputWindow*)v;
  460. // T->oStatus->value("Select file to load...");
  461. //}
  462. void InputWindow::cb_RangeTable(Fl_Widget*, void* v){
  463. InputWindow* T = (InputWindow*)v;
  464. // Spawn a new RangeWindow using the current solution to populate it.
  465. if (T->gsln != NULL && T->gsln->sln != NULL){
  466. new RangeWindow(600,400,T->gsln);
  467. }
  468. else {
  469. T->oStatus->value("Error creating Range Window. Unknown Error.");
  470. }
  471. }
  472. // Implement the paste function. This I did actually figure out how to do.
  473. // The Cut function isn't working yet, but Ctrl-C and Ctrl-V are fortunately
  474. // built into FLTK, so they both work.
  475. void InputWindow::cb_Paste(Fl_Widget* r, void* v){
  476. InputWindow* T = (InputWindow*)v;
  477. T->Paste();
  478. }
  479. void InputWindow::cb_Copy(Fl_Widget* r, void* v){
  480. InputWindow* T = (InputWindow*)v;
  481. T->Copy();
  482. }
  483. void InputWindow::Paste(){
  484. Fl::paste(*this,1);
  485. }
  486. void InputWindow::Copy(){
  487. //int len = Fl::event_length();
  488. //Fl::copy(Fl::event_text(),len,1);
  489. //printf("\nLENGTH: %d Text: %s",len,Fl::event_text());
  490. // 2nd try?
  491. // this->handle(FL_CTRL + 'c');
  492. // Can't figure out how to do this?? very strange...
  493. }
  494. void InputWindow::cb_HelpWindow(Fl_Widget* r, void* vtt){
  495. // Spawn a new help window, this will show whatever is in HelpFile.html
  496. Fl_Help_Dialog* hd = new Fl_Help_Dialog();
  497. hd->load("HelpFile.html");
  498. hd->show();
  499. }
  500. void InputWindow::cb_LicenseWindow(Fl_Widget* r, void*v){
  501. // The LicenseWindow has all the license hard-coded into it,
  502. // so we just need to spawn it and forget about it.
  503. // I don't think this will make a memory leak since it will
  504. // call it's own destructor when it exits.
  505. new LicenseWindow();
  506. }
  507. void InputWindow::cb_AboutWindow(Fl_Widget*,void*v){
  508. // Spawn a new AboutWindow.
  509. new AboutWindow();
  510. }
  511. void InputWindow::cb_Save(Fl_Widget*, void*v){
  512. // If we save the whole solution its like 4mb, so just save the parameters
  513. // and we can regenerate the solution after we reload the parameters.
  514. InputWindow* T = (InputWindow*)v;
  515. if (T->gsln != NULL){
  516. // Get the file name we want to save the data as, using the FLTK standard file picker function.
  517. char* fname=NULL;
  518. fname = fl_file_chooser("Please select a location to save the data.","*.gbc","OutputData.gbc",0);
  519. if (fname==NULL) return;
  520. // Open the file for binary writing.
  521. FILE* ofile = fopen(fname,"wb");
  522. // Write the current solution class to the file, then close it.
  523. int wrote;
  524. wrote=fwrite(T->gsln,1,sizeof(GBCSolution),ofile);
  525. fclose(ofile);
  526. // Update the status display to show our success.
  527. if (wrote == sizeof(GBCSolution)){
  528. T->oStatus->value("GNU Ballistic Computer: File saved successfully.");
  529. }
  530. else {
  531. T->oStatus->value("GNU Ballistic Computer: There was an error writing the file. Please check the path and try again.");
  532. }
  533. }
  534. else {
  535. T->oStatus->value("GNU Ballistic Computer: Can not save, since the solution \nis not yet created. Please create the solution using the \n'Solve' button before you save it.");
  536. }
  537. return;
  538. }
  539. void InputWindow::cb_Open(Fl_Widget* o, void*v){
  540. InputWindow* T = (InputWindow*)v;
  541. // A solution for locally working with gsln (hence the name lsln)
  542. GBCSolution* lsln = NULL;
  543. // Get the file name to load
  544. char* fname=NULL;
  545. fname = fl_file_chooser("Please select a file to open.","*.gbc","",0);
  546. if (fname==NULL) {
  547. T->oStatus->value("GNU Ballistic Computer: Error opening file!");
  548. return;
  549. }
  550. // and open it for binary read.
  551. FILE* ofile = fopen(fname,"rb");
  552. // Free an old solution if there is one, because we want to
  553. // write over it.
  554. if (T->gsln != NULL) {
  555. free(T->gsln);
  556. T->gsln=NULL;
  557. }
  558. // Allocate some space for the loaded solution.
  559. if (lsln != NULL) {
  560. free(lsln);
  561. lsln=NULL;
  562. }
  563. // Assign some new memory for lsln.
  564. lsln = (GBCSolution*)malloc(sizeof(GBCSolution));
  565. if (lsln==NULL){
  566. T->oStatus->value("GNU Ballistic Computer: Memory allocation error.");
  567. return;
  568. }
  569. // Read the GBCSolution class from the file and load it into program
  570. // memory. check to make sure we read the right amount of data.
  571. int read;
  572. read=fread(lsln,1,sizeof(GBCSolution),ofile);
  573. fclose(ofile);
  574. if (read!=sizeof(GBCSolution)){
  575. T->oStatus->value("GNU Ballistic Computer: Error reading file data!\nPlease ensure the file is a valid GNUBC solution.");
  576. if (lsln!=NULL) {
  577. free(lsln);
  578. lsln=NULL;
  579. }
  580. if (T->gsln!=NULL) {
  581. free(T->gsln);
  582. T->gsln=NULL;
  583. }
  584. return;
  585. }
  586. // Set the parent's solution pointer to the local one we just imported.
  587. T->gsln=lsln;
  588. // Load the solution data into the INPUT fields in the InputWindow.
  589. char buff[1024];
  590. T->inName->value(lsln->Name());
  591. sprintf(buff,"%.3f",lsln->BC()); T->inBC->value(buff);
  592. sprintf(buff,"%.2f",lsln->SightHeight()); T->inSH->value(buff);
  593. sprintf(buff,"%d",lsln->MuzzleVelocity()); T->inMV->value(buff);
  594. sprintf(buff,"%d",lsln->ShootingAngle()); T->inAngle->value(buff);
  595. sprintf(buff,"%d",lsln->ZeroRange()); T->inZero->value(buff);
  596. sprintf(buff,"%d",lsln->WindSpeed()); T->inVwind->value(buff);
  597. sprintf(buff,"%d",lsln->WindAngle()); T->inAwind->value(buff);
  598. sprintf(buff,"%d",lsln->Temp()); T->inTemp->value(buff);
  599. sprintf(buff,"%.2f",lsln->Pressure()); T->inPressure->value(buff);
  600. sprintf(buff,"%d",lsln->Humidity()); T->inHumidity->value(buff);
  601. sprintf(buff,"%d",lsln->Altitude()); T->inAltitude->value(buff);
  602. sprintf(buff,"%d",lsln->Weight()); T->inWeight->value(buff);
  603. T->ckWeather->value(lsln->UseWeather());
  604. T->cb_ckWeather(o,v);
  605. T->inG1->value(0);
  606. T->inG2->value(0);
  607. T->inG5->value(0);
  608. T->inG6->value(0);
  609. T->inG7->value(0);
  610. T->inG8->value(0);
  611. if (lsln->df==G1) T->inG1->set();
  612. if (lsln->df==G2) T->inG2->set();
  613. if (lsln->df==G5) T->inG5->set();
  614. if (lsln->df==G6) T->inG6->set();
  615. if (lsln->df==G7) T->inG7->set();
  616. if (lsln->df==G8) T->inG8->set();
  617. // We don't actually have a valid solution, so make sure to set the solution
  618. // double* pointer to NULL before we call solve.
  619. T->gsln->sln=NULL;
  620. // And now solve the loaded parameters.
  621. DisableMenu(T);
  622. T->cb_Solve(o,v);
  623. // Finally inform the user of our success.
  624. T->oStatus->value("GNU Ballistics Computer: File loaded successfully.");
  625. return;
  626. }
  627. void InputWindow::cb_Plot(Fl_Widget* o, void* v){
  628. InputWindow* T = (InputWindow*)v;
  629. GBCSolution* sln = T->gsln;
  630. GBCSolution* lmem1 = T->mem1;
  631. GBCSolution* lmem2 = T->mem2;
  632. new PlotWindow(700,500,sln,lmem1,lmem2);
  633. }
  634. void InputWindow::cb_Store1(Fl_Widget* o, void* v){
  635. InputWindow* T = (InputWindow*)v;
  636. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 1");
  637. if (T->mem1 != NULL) {
  638. if (T->mem1->sln!=NULL) free (T->mem1->sln);
  639. delete(T->mem1);
  640. }
  641. if (T->Smem1!= NULL) free(T->Smem1);
  642. T->mem1=T->gsln;
  643. T->Smem1=T->Solution;
  644. T->gsln=NULL;
  645. T->Solution=NULL;
  646. // Turn the label red to show it's been used.
  647. Fl_Menu_Item* mp;
  648. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+1]);
  649. mp->labelcolor(FL_RED);
  650. cb_Solve(o,v);
  651. }
  652. void InputWindow::cb_Store2(Fl_Widget* o, void* v){
  653. InputWindow* T = (InputWindow*)v;
  654. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 2");
  655. if (T->mem2 != NULL) {
  656. if (T->mem2->sln!=NULL) free(T->mem2->sln);
  657. delete(T->mem2);
  658. }
  659. if (T->Smem2!= NULL) free(T->Smem2);
  660. T->mem2=T->gsln;
  661. T->Smem2=T->Solution;
  662. T->gsln=NULL;
  663. T->Solution=NULL;
  664. // Turn the label blue to indicate it's been used.
  665. Fl_Menu_Item* mp;
  666. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+2]);
  667. mp->labelcolor(FL_RED);
  668. cb_Solve(o,v);
  669. }
  670. void InputWindow::cb_Store3(Fl_Widget* o, void* v){
  671. InputWindow* T = (InputWindow*)v;
  672. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 3");
  673. if (T->mem3 != NULL) {
  674. if (T->mem3->sln!=NULL) free(T->mem3->sln);
  675. delete(T->mem3);
  676. }
  677. if (T->Smem3!= NULL) free(T->Smem3);
  678. T->mem3=T->gsln;
  679. T->Smem3=T->Solution;
  680. T->gsln=NULL;
  681. T->Solution=NULL;
  682. // Turn the label blue to indicate it's been used.
  683. Fl_Menu_Item* mp;
  684. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+3]);
  685. mp->labelcolor(FL_RED);
  686. cb_Solve(o,v);
  687. }
  688. void InputWindow::cb_Store4(Fl_Widget* o, void* v){
  689. InputWindow* T = (InputWindow*)v;
  690. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 4");
  691. if (T->mem4 != NULL) {
  692. if (T->mem4->sln!=NULL) free(T->mem4->sln);
  693. delete(T->mem4);
  694. }
  695. if (T->Smem4!= NULL) free(T->Smem4);
  696. T->mem4=T->gsln;
  697. T->Smem4=T->Solution;
  698. T->gsln=NULL;
  699. T->Solution=NULL;
  700. // Turn the label blue to indicate it's been used.
  701. Fl_Menu_Item* mp;
  702. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+4]);
  703. mp->labelcolor(FL_RED);
  704. cb_Solve(o,v);
  705. }
  706. void InputWindow::cb_Store5(Fl_Widget* o, void* v){
  707. InputWindow* T = (InputWindow*)v;
  708. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 5");
  709. if (T->mem5 != NULL) {
  710. if (T->mem5->sln!=NULL) free(T->mem5->sln);
  711. delete(T->mem5);
  712. }
  713. if (T->Smem5!= NULL) free(T->Smem5);
  714. T->mem5=T->gsln;
  715. T->Smem5=T->Solution;
  716. T->gsln=NULL;
  717. T->Solution=NULL;
  718. // Turn the label blue to indicate it's been used.
  719. Fl_Menu_Item* mp;
  720. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+5]);
  721. mp->labelcolor(FL_RED);
  722. cb_Solve(o,v);
  723. }
  724. void InputWindow::cb_Store6(Fl_Widget* o, void* v){
  725. InputWindow* T = (InputWindow*)v;
  726. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 6");
  727. if (T->mem6 != NULL) {
  728. if (T->mem6->sln!=NULL) free(T->mem6->sln);
  729. delete(T->mem6);
  730. }
  731. if (T->Smem6!= NULL) free(T->Smem6);
  732. T->mem6=T->gsln;
  733. T->Smem6=T->Solution;
  734. T->gsln=NULL;
  735. T->Solution=NULL;
  736. // Turn the label blue to indicate it's been used.
  737. Fl_Menu_Item* mp;
  738. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+6]);
  739. mp->labelcolor(FL_RED);
  740. cb_Solve(o,v);
  741. }
  742. void InputWindow::cb_Store7(Fl_Widget* o, void* v){
  743. InputWindow* T = (InputWindow*)v;
  744. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 7");
  745. if (T->mem7 != NULL) {
  746. if (T->mem7->sln!=NULL) free(T->mem7->sln);
  747. delete(T->mem7);
  748. }
  749. if (T->Smem7!= NULL) free(T->Smem7);
  750. T->mem7=T->gsln;
  751. T->Smem7=T->Solution;
  752. T->gsln=NULL;
  753. T->Solution=NULL;
  754. // Turn the label blue to indicate it's been used.
  755. Fl_Menu_Item* mp;
  756. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+7]);
  757. mp->labelcolor(FL_RED);
  758. cb_Solve(o,v);
  759. }
  760. void InputWindow::cb_Store8(Fl_Widget* o, void* v){
  761. InputWindow* T = (InputWindow*)v;
  762. T->oStatus->value("GNU Ballistics Computer: Stored to Memory 8");
  763. if (T->mem8 != NULL) {
  764. if (T->mem8->sln!=NULL) free(T->mem8->sln);
  765. delete(T->mem8);
  766. }
  767. if (T->Smem8!= NULL) free(T->Smem8);
  768. T->mem8=T->gsln;
  769. T->Smem8=T->Solution;
  770. T->gsln=NULL;
  771. T->Solution=NULL;
  772. // Turn the label blue to indicate it's been used.
  773. Fl_Menu_Item* mp;
  774. mp=(Fl_Menu_Item*)&(T->menu->menu()[MSTORAGE+8]);
  775. mp->labelcolor(FL_RED);
  776. cb_Solve(o,v);
  777. }
  778. void InputWindow::cb_PBR(Fl_Widget* o, void* v){
  779. InputWindow* T = (InputWindow*)v;
  780. new PBRWindow(T);
  781. }
  782. void InputWindow::cb_Options(Fl_Widget* o, void* v){
  783. //InputWindow* T = (InputWindow*)v;
  784. //new OptionsWindow();
  785. }