main_view.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. #include "main_view.h"
  2. #include <furi.h>
  3. #include <furi_hal.h>
  4. #include <gui/elements.h>
  5. #include "../../lightmeter.h"
  6. #include "../../lightmeter_helper.h"
  7. #define WORKER_TAG "Main View"
  8. static const int iso_numbers[] = {
  9. [ISO_6] = 6,
  10. [ISO_12] = 12,
  11. [ISO_25] = 25,
  12. [ISO_50] = 50,
  13. [ISO_100] = 100,
  14. [ISO_200] = 200,
  15. [ISO_400] = 400,
  16. [ISO_800] = 800,
  17. [ISO_1600] = 1600,
  18. [ISO_3200] = 3200,
  19. [ISO_6400] = 6400,
  20. [ISO_12800] = 12800,
  21. [ISO_25600] = 25600,
  22. [ISO_51200] = 51200,
  23. [ISO_102400] = 102400,
  24. };
  25. static const int nd_numbers[] = {
  26. [ND_0] = 0,
  27. [ND_2] = 2,
  28. [ND_4] = 4,
  29. [ND_8] = 8,
  30. [ND_16] = 16,
  31. [ND_32] = 32,
  32. [ND_64] = 64,
  33. [ND_128] = 128,
  34. [ND_256] = 256,
  35. [ND_512] = 512,
  36. [ND_1024] = 1024,
  37. [ND_2048] = 2048,
  38. [ND_4096] = 4096,
  39. };
  40. const float aperture_numbers[] = {
  41. [AP_1] = 1.0,
  42. [AP_1_4] = 1.4,
  43. [AP_2] = 2.0,
  44. [AP_2_8] = 2.8,
  45. [AP_4] = 4.0,
  46. [AP_5_6] = 5.6,
  47. [AP_8] = 8,
  48. [AP_11] = 11,
  49. [AP_16] = 16,
  50. [AP_22] = 22,
  51. [AP_32] = 32,
  52. [AP_45] = 45,
  53. [AP_64] = 64,
  54. [AP_90] = 90,
  55. [AP_128] = 128,
  56. };
  57. const float speed_numbers[] = {
  58. [SPEED_8000] = 1.0 / 8000, [SPEED_4000] = 1.0 / 4000, [SPEED_2000] = 1.0 / 2000,
  59. [SPEED_1000] = 1.0 / 1000, [SPEED_500] = 1.0 / 500, [SPEED_250] = 1.0 / 250,
  60. [SPEED_125] = 1.0 / 125, [SPEED_60] = 1.0 / 60, [SPEED_48] = 1.0 / 48,
  61. [SPEED_30] = 1.0 / 30, [SPEED_15] = 1.0 / 15, [SPEED_8] = 1.0 / 8,
  62. [SPEED_4] = 1.0 / 4, [SPEED_2] = 1.0 / 2, [SPEED_1S] = 1.0,
  63. [SPEED_2S] = 2.0, [SPEED_4S] = 4.0, [SPEED_8S] = 8.0,
  64. [SPEED_15S] = 15.0, [SPEED_30S] = 30.0,
  65. };
  66. struct MainView {
  67. View* view;
  68. LightMeterMainViewButtonCallback cb_left;
  69. void* cb_context;
  70. };
  71. void lightmeter_main_view_set_left_callback(
  72. MainView* lightmeter_main_view,
  73. LightMeterMainViewButtonCallback callback,
  74. void* context) {
  75. with_view_model(
  76. lightmeter_main_view->view,
  77. MainViewModel * model,
  78. {
  79. UNUSED(model);
  80. lightmeter_main_view->cb_left = callback;
  81. lightmeter_main_view->cb_context = context;
  82. },
  83. true);
  84. }
  85. static void main_view_draw_callback(Canvas* canvas, void* context) {
  86. furi_assert(context);
  87. MainViewModel* model = context;
  88. canvas_clear(canvas);
  89. // draw button
  90. canvas_set_font(canvas, FontSecondary);
  91. elements_button_left(canvas, "Config");
  92. if(!model->lux_only) {
  93. // top row
  94. draw_top_row(canvas, model);
  95. // add f, T values
  96. canvas_set_font(canvas, FontBigNumbers);
  97. // draw f icon and number
  98. canvas_draw_icon(canvas, 15, 17, &I_f_10x14);
  99. draw_aperture(canvas, model);
  100. // draw T icon and number
  101. canvas_draw_icon(canvas, 15, 34, &I_T_10x14);
  102. draw_speed(canvas, model);
  103. // draw ND number
  104. draw_nd_number(canvas, model);
  105. // draw EV number
  106. canvas_set_font(canvas, FontSecondary);
  107. draw_EV_number(canvas, model);
  108. // draw mode indicator
  109. draw_mode_indicator(canvas, model);
  110. } else {
  111. draw_lux_only_mode(canvas, model);
  112. }
  113. }
  114. static void main_view_process(MainView* main_view, InputEvent* event) {
  115. with_view_model(
  116. main_view->view,
  117. MainViewModel * model,
  118. {
  119. if(event->type == InputTypePress) {
  120. if(event->key == InputKeyUp) {
  121. switch(model->current_mode) {
  122. case FIXED_APERTURE:
  123. if(model->aperture < AP_NUM - 1) model->aperture++;
  124. break;
  125. case FIXED_SPEED:
  126. if(model->speed < SPEED_NUM - 1) model->speed++;
  127. break;
  128. default:
  129. break;
  130. }
  131. } else if(event->key == InputKeyDown) {
  132. switch(model->current_mode) {
  133. case FIXED_APERTURE:
  134. if(model->aperture > 0) model->aperture--;
  135. break;
  136. case FIXED_SPEED:
  137. if(model->speed > 0) model->speed--;
  138. break;
  139. default:
  140. break;
  141. }
  142. } else if(event->key == InputKeyOk) {
  143. switch(model->current_mode) {
  144. case FIXED_SPEED:
  145. model->current_mode = FIXED_APERTURE;
  146. break;
  147. case FIXED_APERTURE:
  148. model->current_mode = FIXED_SPEED;
  149. break;
  150. default:
  151. break;
  152. }
  153. }
  154. }
  155. },
  156. true);
  157. }
  158. static bool main_view_input_callback(InputEvent* event, void* context) {
  159. furi_assert(context);
  160. MainView* main_view = context;
  161. bool consumed = false;
  162. if(event->type == InputTypeShort && event->key == InputKeyLeft) {
  163. if(main_view->cb_left) {
  164. main_view->cb_left(main_view->cb_context);
  165. }
  166. consumed = true;
  167. } else if(event->type == InputTypeShort && event->key == InputKeyBack) {
  168. } else {
  169. main_view_process(main_view, event);
  170. consumed = true;
  171. }
  172. return consumed;
  173. }
  174. MainView* main_view_alloc() {
  175. MainView* main_view = malloc(sizeof(MainView));
  176. main_view->view = view_alloc();
  177. view_set_context(main_view->view, main_view);
  178. view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(MainViewModel));
  179. view_set_draw_callback(main_view->view, main_view_draw_callback);
  180. view_set_input_callback(main_view->view, main_view_input_callback);
  181. return main_view;
  182. }
  183. void main_view_free(MainView* main_view) {
  184. furi_assert(main_view);
  185. view_free(main_view->view);
  186. free(main_view);
  187. }
  188. View* main_view_get_view(MainView* main_view) {
  189. furi_assert(main_view);
  190. return main_view->view;
  191. }
  192. void main_view_set_lux(MainView* main_view, float val) {
  193. furi_assert(main_view);
  194. with_view_model(
  195. main_view->view, MainViewModel * model, { model->lux = val; }, true);
  196. }
  197. void main_view_set_EV(MainView* main_view, float val) {
  198. furi_assert(main_view);
  199. with_view_model(
  200. main_view->view, MainViewModel * model, { model->EV = val; }, true);
  201. }
  202. void main_view_set_response(MainView* main_view, bool val) {
  203. furi_assert(main_view);
  204. with_view_model(
  205. main_view->view, MainViewModel * model, { model->response = val; }, true);
  206. }
  207. void main_view_set_iso(MainView* main_view, int iso) {
  208. furi_assert(main_view);
  209. with_view_model(
  210. main_view->view, MainViewModel * model, { model->iso = iso; }, true);
  211. }
  212. void main_view_set_nd(MainView* main_view, int nd) {
  213. furi_assert(main_view);
  214. with_view_model(
  215. main_view->view, MainViewModel * model, { model->nd = nd; }, true);
  216. }
  217. void main_view_set_aperture(MainView* main_view, int aperture) {
  218. furi_assert(main_view);
  219. with_view_model(
  220. main_view->view, MainViewModel * model, { model->aperture = aperture; }, true);
  221. }
  222. void main_view_set_speed(MainView* main_view, int speed) {
  223. furi_assert(main_view);
  224. with_view_model(
  225. main_view->view, MainViewModel * model, { model->speed = speed; }, true);
  226. }
  227. void main_view_set_dome(MainView* main_view, bool dome) {
  228. furi_assert(main_view);
  229. with_view_model(
  230. main_view->view, MainViewModel * model, { model->dome = dome; }, true);
  231. }
  232. void main_view_set_lux_only(MainView* main_view, bool lux_only) {
  233. furi_assert(main_view);
  234. with_view_model(
  235. main_view->view, MainViewModel * model, { model->lux_only = lux_only; }, true);
  236. }
  237. bool main_view_get_dome(MainView* main_view) {
  238. furi_assert(main_view);
  239. bool val = false;
  240. with_view_model(
  241. main_view->view, MainViewModel * model, { val = model->dome; }, true);
  242. return val;
  243. }
  244. void draw_top_row(Canvas* canvas, MainViewModel* context) {
  245. MainViewModel* model = context;
  246. char str[12];
  247. if(!model->response) {
  248. canvas_draw_box(canvas, 0, 0, 128, 12);
  249. canvas_set_color(canvas, ColorWhite);
  250. canvas_set_font(canvas, FontPrimary);
  251. canvas_draw_str(canvas, 24, 10, "No sensor found");
  252. canvas_set_color(canvas, ColorBlack);
  253. } else {
  254. model->iso_val = iso_numbers[model->iso];
  255. if(model->nd > 0) model->iso_val /= nd_numbers[model->nd];
  256. if(model->lux > 0) {
  257. if(model->current_mode == FIXED_APERTURE) {
  258. model->speed_val = 100 * pow(aperture_numbers[model->aperture], 2) /
  259. (double)model->iso_val / pow(2, model->EV);
  260. } else {
  261. model->aperture_val = sqrt(
  262. pow(2, model->EV) * (double)model->iso_val *
  263. (double)speed_numbers[model->speed] / 100);
  264. }
  265. }
  266. // TODO when T:30, f/0 instead of f/128
  267. canvas_draw_line(canvas, 0, 10, 128, 10);
  268. canvas_set_font(canvas, FontPrimary);
  269. // metering mode A – ambient, F – flash
  270. // canvas_draw_str_aligned(canvas, 1, 1, AlignLeft, AlignTop, "A");
  271. snprintf(str, sizeof(str), "ISO: %d", iso_numbers[model->iso]);
  272. canvas_draw_str_aligned(canvas, 19, 1, AlignLeft, AlignTop, str);
  273. canvas_set_font(canvas, FontSecondary);
  274. snprintf(str, sizeof(str), "lx: %.0f", (double)model->lux);
  275. canvas_draw_str_aligned(canvas, 87, 2, AlignLeft, AlignTop, str);
  276. }
  277. }
  278. void draw_aperture(Canvas* canvas, MainViewModel* context) {
  279. MainViewModel* model = context;
  280. char str[12];
  281. switch(model->current_mode) {
  282. case FIXED_APERTURE:
  283. if(model->response) {
  284. if(model->aperture < AP_8) {
  285. snprintf(str, sizeof(str), "/%.1f", (double)aperture_numbers[model->aperture]);
  286. } else {
  287. snprintf(str, sizeof(str), "/%.0f", (double)aperture_numbers[model->aperture]);
  288. }
  289. } else {
  290. snprintf(str, sizeof(str), " ---");
  291. }
  292. canvas_draw_str_aligned(canvas, 27, 15, AlignLeft, AlignTop, str);
  293. break;
  294. case FIXED_SPEED:
  295. if(model->aperture_val < aperture_numbers[0] || !model->response) {
  296. snprintf(str, sizeof(str), " ---");
  297. } else if(model->aperture_val < aperture_numbers[AP_8]) {
  298. snprintf(str, sizeof(str), "/%.1f", (double)normalizeAperture(model->aperture_val));
  299. } else {
  300. snprintf(str, sizeof(str), "/%.0f", (double)normalizeAperture(model->aperture_val));
  301. }
  302. canvas_draw_str_aligned(canvas, 27, 15, AlignLeft, AlignTop, str);
  303. break;
  304. default:
  305. break;
  306. }
  307. }
  308. void draw_speed(Canvas* canvas, MainViewModel* context) {
  309. MainViewModel* model = context;
  310. char str[12];
  311. switch(model->current_mode) {
  312. case FIXED_APERTURE:
  313. if(model->lux > 0 && model->response) {
  314. if(model->speed_val < 1 && model->speed_val > 0) {
  315. snprintf(str, sizeof(str), ":1/%.0f", 1 / (double)normalizeTime(model->speed_val));
  316. } else {
  317. snprintf(str, sizeof(str), ":%.0f", (double)normalizeTime(model->speed_val));
  318. }
  319. } else {
  320. snprintf(str, sizeof(str), " ---");
  321. }
  322. canvas_draw_str_aligned(canvas, 27, 34, AlignLeft, AlignTop, str);
  323. break;
  324. case FIXED_SPEED:
  325. if(model->response) {
  326. if(model->speed < SPEED_1S) {
  327. snprintf(str, sizeof(str), ":1/%.0f", 1 / (double)speed_numbers[model->speed]);
  328. } else {
  329. snprintf(str, sizeof(str), ":%.0f", (double)speed_numbers[model->speed]);
  330. }
  331. } else {
  332. snprintf(str, sizeof(str), " ---");
  333. }
  334. canvas_draw_str_aligned(canvas, 27, 34, AlignLeft, AlignTop, str);
  335. break;
  336. default:
  337. break;
  338. }
  339. }
  340. void draw_mode_indicator(Canvas* canvas, MainViewModel* context) {
  341. MainViewModel* model = context;
  342. switch(model->current_mode) {
  343. case FIXED_SPEED:
  344. canvas_set_font(canvas, FontBigNumbers);
  345. canvas_draw_str_aligned(canvas, 3, 36, AlignLeft, AlignTop, "*");
  346. break;
  347. case FIXED_APERTURE:
  348. canvas_set_font(canvas, FontBigNumbers);
  349. canvas_draw_str_aligned(canvas, 3, 17, AlignLeft, AlignTop, "*");
  350. break;
  351. default:
  352. break;
  353. }
  354. }
  355. void draw_nd_number(Canvas* canvas, MainViewModel* context) {
  356. MainViewModel* model = context;
  357. char str[9];
  358. canvas_set_font(canvas, FontSecondary);
  359. if(model->response) {
  360. snprintf(str, sizeof(str), "ND: %d", nd_numbers[model->nd]);
  361. } else {
  362. snprintf(str, sizeof(str), "ND: ---");
  363. }
  364. canvas_draw_str_aligned(canvas, 87, 20, AlignLeft, AlignBottom, str);
  365. }
  366. void draw_EV_number(Canvas* canvas, MainViewModel* context) {
  367. MainViewModel* model = context;
  368. char str[7];
  369. if(model->lux > 0 && model->response) {
  370. snprintf(str, sizeof(str), "EV: %1.0f", (double)model->EV);
  371. canvas_draw_str_aligned(canvas, 87, 29, AlignLeft, AlignBottom, str);
  372. } else {
  373. canvas_draw_str_aligned(canvas, 87, 29, AlignLeft, AlignBottom, "EV: --");
  374. }
  375. }
  376. void draw_lux_only_mode(Canvas* canvas, MainViewModel* context) {
  377. MainViewModel* model = context;
  378. if(!model->response) {
  379. canvas_draw_box(canvas, 0, 0, 128, 12);
  380. canvas_set_color(canvas, ColorWhite);
  381. canvas_set_font(canvas, FontPrimary);
  382. canvas_draw_str(canvas, 24, 10, "No sensor found");
  383. canvas_set_color(canvas, ColorBlack);
  384. } else {
  385. char str[12];
  386. canvas_set_font(canvas, FontPrimary);
  387. canvas_draw_line(canvas, 0, 10, 128, 10);
  388. canvas_draw_str_aligned(canvas, 64, 1, AlignCenter, AlignTop, "Lux meter mode");
  389. canvas_set_font(canvas, FontBigNumbers);
  390. snprintf(str, sizeof(str), "%.0f", (double)model->lux);
  391. canvas_draw_str_aligned(canvas, 80, 32, AlignRight, AlignCenter, str);
  392. canvas_set_font(canvas, FontSecondary);
  393. canvas_draw_str_aligned(canvas, 85, 39, AlignLeft, AlignBottom, "Lux");
  394. }
  395. }