1 /* Class FoodRanking */
2
3 /*
4 NUT nutrition software
5 Copyright (C) 1996-2014 by Jim Jozwiak.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22 #include <FL/Fl.H>
23 #include "FoodRanking.h"
24 #include "util.h"
25 #ifndef __hpux
26 #include <stdint.h>
27 #endif
28 #include <string.h>
29
30 static intptr_t the_ranking;
31 static int lastnut, lastscreen, food_group = -1, minimize = -1;
32
33 static FoodRanking *who_we_are;
34
the_cb(Fl_Widget * which,void * one)35 static void the_cb(Fl_Widget *which, void *one)
36 {
37 the_ranking = (intptr_t) one;
38 food_group = -1;
39 minimize = -1;
40 who_we_are->initial_meal_add = 1;
41 who_we_are->populate(lastnut,lastscreen);
42 }
43
44 static Fl_Menu_Item pulldown[] = {
45 {"per 100 Grams", 0, the_cb, (void*)0},
46 {"per 100 Grams Dry Weight", 0, the_cb, (void*)1},
47 {"per 100 Grams within Food Group ?", 0, the_cb, (void*)2},
48 {"per 100 Calories", 0, the_cb, (void*)3},
49 {"per Serving", 0, the_cb, (void*)4},
50 {"per Serving, Minimize Nutrient ?, \"no data\" instances included", 0, the_cb, (void*)5},
51 {"per Serving, Minimize Nutrient ?, \"no data\" instances excluded", 0, the_cb, (void*)6},
52 {"per Daily Recorded Meals", 0, the_cb, (void*)7},
53 {0}};
54
FoodRanking(int x,int y,int w,int h,Fl_Color widgetcolor,TheStory * ts)55 FoodRanking::FoodRanking (int x, int y, int w, int h, Fl_Color widgetcolor, TheStory *ts) : Fl_Group (x, y, w, h)
56 {
57 int i;
58 story = ts;
59 this->color(widgetcolor);
60 mb = new Fl_Menu_Button(x,y,w,h/23);
61 mb->color(fl_lighter(widgetcolor));
62 mb->clear_visible_focus();
63 mb->align(FL_ALIGN_INSIDE|FL_ALIGN_CENTER);
64 mb->menu(pulldown);
65 ancient_scroll = new Nut_Scroll(x,y+h/23,w,22*h/23);
66 ancient_scroll->type(Fl_Scroll::VERTICAL);
67 ancient_scroll->color(scheme_color(widgetcolor));
68 foodpack = new Nut_Pack(x,y+h/23,17*w/18,22*h/23);
69 foodpack->end();
70 ancient_scroll->end();
71 for (i = 0; i < FoodCount; i++)
72 {
73 FoodButtonArray[i] = new FoodButton(x,y,17*w/27,h/23, FoodIndex[i]);
74 foodpack->add(FoodButtonArray[i]);
75 foodpack->remove(FoodButtonArray[i]);
76 }
77 this->end();
78 if (meal_count(options.temp_meal_root) > 0)
79 {
80 the_ranking = 7;
81 initial_meal_add = 1;
82 }
83 else
84 {
85 the_ranking = 0;
86 initial_meal_add = 0;
87 }
88 who_we_are = this;
89 }
90
populate(int num,int screen)91 void FoodRanking::populate(int num, int screen)
92 {
93 lastnut = num;
94 lastscreen = screen;
95 if (initial_meal_add == 0 && meal_count(options.temp_meal_root) > 0)
96 {
97 the_ranking = 7;
98 initial_meal_add = 1;
99 }
100 switch (the_ranking)
101 {
102 case 0: per_100_grams(num, screen);
103 break;
104 case 1: per_100_grams_dry_weight(num, screen);
105 break;
106 case 2: per_100_grams_within_food_group(num, screen);
107 break;
108 case 3: per_100_calories(num, screen);
109 break;
110 case 4: per_serving(num, screen);
111 break;
112 case 5: per_serving_minimize(num, screen, 1);
113 break;
114 case 6: per_serving_minimize(num, screen, 0);
115 break;
116 default: per_daily_recorded_meals(num, screen);
117 break;
118 }
119 }
120
set_food_group(int fg)121 void FoodRanking::set_food_group(int fg)
122 {
123 food_group = fg;
124 per_100_grams_within_food_group(lastnut, lastscreen);
125 }
126
set_minimize(int min)127 void FoodRanking::set_minimize(int min)
128 {
129 minimize = min;
130 per_serving_minimize(lastnut, lastscreen, -1);
131 }
132
food_present(int foodno)133 void FoodRanking::food_present(int foodno)
134 {
135 static int count = 0;
136 static FoodButton *array[600];
137
138 if (foodno == -1)
139 {
140 for (int i = 0; i < count; i++) foodpack->remove(array[i]);
141 count = 0;
142 }
143
144 if (foodno > -1 && count < 600)
145 {
146 foodpack->add(FoodButtonArray[foodno]);
147 array[count] = FoodButtonArray[foodno];
148 count++;
149 }
150 }
151
max_array(void)152 int FoodRanking::max_array(void)
153 {
154 int count, i = 0;
155 for ( count = 1 ; count < FoodCount ; count++ ) if (abacus[count] > abacus[i]) i = count;
156 return i;
157 }
158
per_daily_recorded_meals(int num,int screen)159 void FoodRanking::per_daily_recorded_meals(int num, int screen)
160 {
161 int count, meals = 0, maxmeal, max = 0;
162 float days;
163 struct food *food_ptr = &food_root;
164 struct meal *meal_ptr = options.temp_meal_root;
165 char meal_date[9], meal = '\0';
166 mb->label("Foods Ranked per Daily Recorded Meals");
167 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
168 food_present(-1);
169 if (meal_count(meal_ptr) > 0)
170 {
171 if ( meal_count(options.temp_meal_root) < options.defanal || options.defanal == 0)
172 {
173 days = (float) meal_count(options.temp_meal_root) / (float) options.mealsperday;
174 maxmeal = meal_count(options.temp_meal_root);
175 }
176 else
177 {
178 days = (float) options.defanal / (float) options.mealsperday;
179 maxmeal = options.defanal;
180 }
181 while ( meal_ptr->next != NULL && meals <= maxmeal )
182 {
183 meal_ptr = meal_ptr->next;
184 if (strcmp(meal_date,meal_ptr->meal_date) != 0 || meal != meal_ptr->meal)
185 {
186 strcpy(meal_date,meal_ptr->meal_date);
187 meal = meal_ptr->meal;
188 meals++;
189 }
190 if ( meals <= maxmeal ) abacus[meal_ptr->food_no] += meal_ptr->grams;
191 }
192 for (count = 0 ; count < FoodCount ; count++)
193 {
194 abacus[count] /= days;
195 abacus[count] *= FoodIndex[count]->nutrient[num];
196 }
197 max = max_array();
198 count = 0;
199 while (abacus[max] != 0 && count < 600)
200 {
201 food_ptr = food_number(max);
202 FoodButtonArray[max]->grams(abacus[max] / food_ptr->nutrient[num]);
203 food_present(max);
204 count++;
205 abacus[max] = 0;
206 max = max_array();
207 }
208 }
209 foodpack->redraw();
210 ancient_scroll->redraw();
211 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
212 ancient_scroll->position(0,0);
213 #else
214 ancient_scroll->scroll_to(0,0);
215 #endif
216 Fl::flush();
217 }
218
per_100_grams(int num,int screen)219 void FoodRanking::per_100_grams(int num, int screen)
220 {
221 int count, max = 0;
222 struct food *food_ptr = &food_root;
223 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
224 food_present(-1);
225 mb->label("Foods Ranked per 100 Grams");
226 for (count = 0 ; count < FoodCount ; count++) abacus[count] = FoodIndex[count]->nutrient[num];
227 max = max_array();
228 count = 0;
229 while (abacus[max] != 0 && count < 600)
230 {
231 food_ptr = food_number(max);
232 FoodButtonArray[max]->grams(100);
233 food_present(max);
234 count++;
235 abacus[max] = 0;
236 max = max_array();
237 }
238 foodpack->redraw();
239 ancient_scroll->redraw();
240 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
241 ancient_scroll->position(0,0);
242 #else
243 ancient_scroll->scroll_to(0,0);
244 #endif
245 Fl::flush();
246 }
247
per_100_grams_dry_weight(int num,int screen)248 void FoodRanking::per_100_grams_dry_weight(int num, int screen)
249 {
250 int count, max = 0;
251 struct food *food_ptr = &food_root;
252 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
253 food_present(-1);
254 mb->label("Foods Ranked per 100 Grams Dry Weight");
255 if (num != WATER)
256 {
257 for (count = 0 ; count < FoodCount ; count++)
258 {
259 abacus[count] = (100 * FoodIndex[count]->nutrient[num]) / (100 - FoodIndex[count]->nutrient[WATER]);
260 if (!(FoodIndex[count]->nutrient[WATER] < 100)) abacus[count] = 0;
261 }
262 max = max_array();
263 count = 0;
264 while (abacus[max] != 0 && count < 600)
265 {
266 food_ptr = food_number(max);
267 FoodButtonArray[max]->grams(100 * abacus[max] / food_ptr->nutrient[num]);
268 food_present(max);
269 count++;
270 abacus[max] = 0;
271 max = max_array();
272 }
273 }
274 foodpack->redraw();
275 ancient_scroll->redraw();
276 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
277 ancient_scroll->position(0,0);
278 #else
279 ancient_scroll->scroll_to(0,0);
280 #endif
281 Fl::flush();
282 }
283
per_100_grams_within_food_group(int num,int screen)284 void FoodRanking::per_100_grams_within_food_group(int num, int screen)
285 {
286 if (food_group == -1)
287 {
288 story->choose_food_group();
289 return;
290 }
291 int count, max = 0;
292 struct food *food_ptr = &food_root;
293 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
294 food_present(-1);
295 sprintf(mbbuf,"Foods Ranked per 100 Grams within \"%s\"",FdGrp[food_group]);
296 mb->label(mbbuf);
297 for (count = 0 ; count < FoodCount ; count++) if (FoodIndex[count]->fdgrp == food_group) abacus[count] = FoodIndex[count]->nutrient[num];
298 max = max_array();
299 count = 0;
300 while (abacus[max] != 0 && count < 600)
301 {
302 food_ptr = food_number(max);
303 FoodButtonArray[max]->grams(100);
304 food_present(max);
305 count++;
306 abacus[max] = 0;
307 max = max_array();
308 }
309 foodpack->redraw();
310 ancient_scroll->redraw();
311 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
312 ancient_scroll->position(0,0);
313 #else
314 ancient_scroll->scroll_to(0,0);
315 #endif
316 Fl::flush();
317 }
318
per_serving_minimize(int num,int screen,int type)319 void FoodRanking::per_serving_minimize(int num, int screen, int type)
320 {
321 static int savetype;
322 if (minimize == -1)
323 {
324 savetype = type;
325 story->choose_minimize();
326 return;
327 }
328 if (type != -1) savetype = type;
329 int count, max = 0;
330 struct food *food_ptr = &food_root;
331 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
332 food_present(-1);
333 if (savetype == 1) sprintf(mbbuf,"Foods Ranked per Serving, Minimize %s, \"no data\" instances included",Nutrient[minimize]);
334 else sprintf(mbbuf,"Foods Ranked per Serving, Minimize %s, \"no data\" instances excluded",Nutrient[minimize]);
335 mb->label(mbbuf);
336 float minavg = 0;
337 int mincount = 0;
338
339 for (count = 0 ; count < FoodCount ; count++)
340 {
341 food_ptr = food_ptr->next;
342 if (! test_for_negative_zero(&food_ptr->nutrient[minimize]))
343 {
344 minavg += food_ptr->nutrient[minimize];
345 mincount++;
346 }
347 }
348 if (mincount > 0) minavg /= mincount;
349 food_ptr = &food_root;
350 for (count = 0 ; count < FoodCount ; count++)
351 {
352 food_ptr = food_ptr->next;
353 if (mincount == 0 ||
354 test_for_negative_zero(&food_ptr->nutrient[num]) ||
355 (savetype == 0 && test_for_negative_zero(&food_ptr->nutrient[minimize])) ||
356 minimize == num ||
357 (num == VITE && minimize == TOCPHA) || (num == TOCPHA && minimize == VITE) ||
358 (num == LA && minimize == F18D2) || (num == F18D2 && minimize == LA) ||
359 (num == LA && minimize == F18D2CN6) || (num == F18D2CN6 && minimize == LA) ||
360 (num == AA && minimize == F20D4) || (num == F20D4 && minimize == AA) ||
361 (num == ALA && minimize == F18D3) || (num == F18D3 && minimize == ALA) ||
362 (num == ALA && minimize == F18D3CN3) || (num == F18D3CN3 && minimize == ALA) ||
363 (num == EPA && minimize == F20D5) || (num == F20D5 && minimize == EPA) ||
364 (num == DHA && minimize == F22D6) || (num == F22D6 && minimize == DHA))
365 abacus[count] = 0;
366 else abacus[count] = (food_ptr->grams / -100 * food_ptr->nutrient[num]) * ((food_ptr->grams / 100 * food_ptr->nutrient[minimize] / minavg) - 1);
367 }
368
369 max = max_array();
370 count = 0;
371 while (abacus[max] != 0 && count < 600)
372 {
373 food_ptr = food_number(max);
374 FoodButtonArray[max]->grams(food_ptr->grams);
375 food_present(max);
376 count++;
377 abacus[max] = 0;
378 max = max_array();
379 }
380 foodpack->redraw();
381 ancient_scroll->redraw();
382 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
383 ancient_scroll->position(0,0);
384 #else
385 ancient_scroll->scroll_to(0,0);
386 #endif
387 Fl::flush();
388 }
389
per_100_calories(int num,int screen)390 void FoodRanking::per_100_calories(int num, int screen)
391 {
392 int count, max = 0;
393 struct food *food_ptr = &food_root;
394 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
395 food_present(-1);
396 mb->label("Foods Ranked per 100 Calories");
397 if (num != ENERC_KCAL && num != ENERC_KJ)
398 {
399 for (count = 0 ; count < FoodCount ; count++)
400 {
401 if (FoodIndex[count]->nutrient[ENERC_KCAL] > 0) abacus[count] = 100 * FoodIndex[count]->nutrient[num] / FoodIndex[count]->nutrient[ENERC_KCAL];
402 else abacus[count] = 0;
403 }
404 max = max_array();
405 count = 0;
406 while (abacus[max] != 0 && count < 600)
407 {
408 food_ptr = food_number(max);
409 FoodButtonArray[max]->grams(100 * abacus[max] / food_ptr->nutrient[num]);
410 food_present(max);
411 count++;
412 abacus[max] = 0;
413 max = max_array();
414 }
415 }
416 foodpack->redraw();
417 ancient_scroll->redraw();
418 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
419 ancient_scroll->position(0,0);
420 #else
421 ancient_scroll->scroll_to(0,0);
422 #endif
423 Fl::flush();
424 }
425
per_serving(int num,int screen)426 void FoodRanking::per_serving(int num, int screen)
427 {
428 int count, max = 0;
429 struct food *food_ptr = &food_root;
430 for (count = 0 ; count < FoodCount ; count++) abacus[count] = 0;
431 food_present(-1);
432 mb->label("Foods Ranked per Serving");
433 for (count = 0 ; count < FoodCount ; count++) abacus[count] = FoodIndex[count]->grams / 100 * FoodIndex[count]->nutrient[num];
434 max = max_array();
435 count = 0;
436 while (abacus[max] != 0 && count < 600)
437 {
438 food_ptr = food_number(max);
439 FoodButtonArray[max]->grams(food_ptr->grams);
440 food_present(max);
441 count++;
442 abacus[max] = 0;
443 max = max_array();
444 }
445 foodpack->redraw();
446 ancient_scroll->redraw();
447 #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 1
448 ancient_scroll->position(0,0);
449 #else
450 ancient_scroll->scroll_to(0,0);
451 #endif
452 Fl::flush();
453 }
454
reindex_foodbuttons(int foodnum)455 void FoodRanking::reindex_foodbuttons(int foodnum)
456 {
457 for (int i = FoodCount; i > foodnum; i--) FoodButtonArray[i] = FoodButtonArray[i-1];
458 FoodButtonArray[foodnum] = new FoodButton(x(),y(),17*w()/27,h()/23, FoodIndex[foodnum]);
459 foodpack->add(FoodButtonArray[foodnum]);
460 foodpack->remove(FoodButtonArray[foodnum]);
461 }
462
resize(int x,int y,int w,int h)463 void FoodRanking::resize(int x, int y, int w, int h)
464 {
465 int i;
466 Fl_Group::resize(x, y, w, h);
467 mb->labelsize(FL_NORMAL_SIZE);
468 for (i = 0; i < 8; i++) pulldown[i].labelsize(FL_NORMAL_SIZE);
469 for (i = 0; i < FoodCount; i++) FoodButtonArray[i]->resize(x,y,17*w/27,h/23);
470 }
471