My Marlin configs for Fabrikator Mini and CTC i3 Pro B
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

bio_status_screen.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*************************
  2. * bio_status_screen.cpp *
  3. *************************/
  4. /****************************************************************************
  5. * Written By Mark Pelletier 2017 - Aleph Objects, Inc. *
  6. * Written By Marcio Teixeira 2018 - Aleph Objects, Inc. *
  7. * Written By Marcio Teixeira 2019 - Cocoa Press *
  8. * *
  9. * This program is free software: you can redistribute it and/or modify *
  10. * it under the terms of the GNU General Public License as published by *
  11. * the Free Software Foundation, either version 3 of the License, or *
  12. * (at your option) any later version. *
  13. * *
  14. * This program is distributed in the hope that it will be useful, *
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  17. * GNU General Public License for more details. *
  18. * *
  19. * To view a copy of the GNU General Public License, go to the following *
  20. * location: <http://www.gnu.org/licenses/>. *
  21. ****************************************************************************/
  22. #include "../config.h"
  23. #if ENABLED(TOUCH_UI_FTDI_EVE) && (ENABLED(TOUCH_UI_LULZBOT_BIO) || ENABLED(TOUCH_UI_COCOA_PRESS))
  24. #include "screens.h"
  25. #include "../ftdi_eve_lib/extras/poly_ui.h"
  26. #ifdef TOUCH_UI_PORTRAIT
  27. #include "bio_printer_ui_portrait.h"
  28. #else
  29. #include "bio_printer_ui_landscape.h"
  30. #endif
  31. #define GRID_COLS 2
  32. #define GRID_ROWS 9
  33. #define POLY(A) PolyUI::poly_reader_t(A, sizeof(A)/sizeof(A[0]))
  34. const uint8_t shadow_depth = 5;
  35. const float max_speed = 1.00;
  36. const float min_speed = 0.02;
  37. const float emax_speed = 2.00;
  38. const float emin_speed = 0.70;
  39. using namespace FTDI;
  40. using namespace Theme;
  41. using namespace ExtUI;
  42. float StatusScreen::increment;
  43. bool StatusScreen::jog_xy;
  44. bool StatusScreen::fine_motion;
  45. void StatusScreen::unlockMotors() {
  46. injectCommands_P(PSTR("M84 XY"));
  47. jog_xy = false;
  48. }
  49. void StatusScreen::draw_temperature(draw_mode_t what) {
  50. CommandProcessor cmd;
  51. PolyUI ui(cmd, what);
  52. int16_t x, y, h, v;
  53. cmd.tag(15);
  54. if (what & BACKGROUND) {
  55. cmd.cmd(COLOR_RGB(bg_color));
  56. #if ENABLED(TOUCH_UI_LULZBOT_BIO)
  57. // The LulzBot Bio shows the temperature for
  58. // the bed.
  59. #ifdef TOUCH_UI_PORTRAIT
  60. // Draw touch surfaces
  61. ui.bounds(POLY(target_temp), x, y, h, v);
  62. cmd.rectangle(x, y, h, v);
  63. ui.bounds(POLY(actual_temp), x, y, h, v);
  64. cmd.rectangle(x, y, h, v);
  65. #else
  66. ui.bounds(POLY(bed_temp), x, y, h, v);
  67. cmd.rectangle(x, y, h, v);
  68. #endif
  69. ui.bounds(POLY(bed_icon), x, y, h, v);
  70. cmd.rectangle(x, y, h, v);
  71. // Draw bed icon
  72. cmd.cmd(BITMAP_SOURCE(Bed_Heat_Icon_Info))
  73. .cmd(BITMAP_LAYOUT(Bed_Heat_Icon_Info))
  74. .cmd(BITMAP_SIZE (Bed_Heat_Icon_Info))
  75. .cmd(COLOR_RGB(shadow_rgb))
  76. .icon (x + 2, y + 2, h, v, Bed_Heat_Icon_Info, icon_scale * 2)
  77. .cmd(COLOR_RGB(bg_text_enabled))
  78. .icon (x, y, h, v, Bed_Heat_Icon_Info, icon_scale * 2);
  79. #endif
  80. #if ENABLED(TOUCH_UI_COCOA_PRESS)
  81. // The CocoaPress shows the temperature for two
  82. // heating zones, but has no bed temperature
  83. cmd.cmd(COLOR_RGB(bg_text_enabled));
  84. cmd.font(font_medium);
  85. ui.bounds(POLY(zone1_label), x, y, h, v);
  86. cmd.text(x, y, h, v, GET_TEXT_F(MSG_ZONE_1));
  87. ui.bounds(POLY(zone2_label), x, y, h, v);
  88. cmd.text(x, y, h, v, GET_TEXT_F(MSG_ZONE_2));
  89. #endif
  90. #ifdef TOUCH_UI_USE_UTF8
  91. load_utf8_bitmaps(cmd); // Restore font bitmap handles
  92. #endif
  93. }
  94. if (what & FOREGROUND) {
  95. char str[15];
  96. cmd.cmd(COLOR_RGB(bg_text_enabled));
  97. #if ENABLED(TOUCH_UI_LULZBOT_BIO)
  98. cmd.font(font_medium);
  99. #ifdef TOUCH_UI_PORTRAIT
  100. if (!isHeaterIdle(BED) && getTargetTemp_celsius(BED) > 0)
  101. format_temp(str, getTargetTemp_celsius(BED));
  102. else
  103. strcpy_P(str, GET_TEXT(MSG_BED));
  104. ui.bounds(POLY(target_temp), x, y, h, v);
  105. cmd.text(x, y, h, v, str);
  106. format_temp(str, getActualTemp_celsius(BED));
  107. ui.bounds(POLY(actual_temp), x, y, h, v);
  108. cmd.text(x, y, h, v, str);
  109. #else
  110. if (!isHeaterIdle(BED) && getTargetTemp_celsius(BED) > 0)
  111. format_temp_and_temp(str, getActualTemp_celsius(BED), getTargetTemp_celsius(BED));
  112. else
  113. format_temp_and_idle(str, getActualTemp_celsius(BED));
  114. ui.bounds(POLY(bed_temp), x, y, h, v);
  115. cmd.text(x, y, h, v, str);
  116. #endif
  117. #endif
  118. #if ENABLED(TOUCH_UI_COCOA_PRESS)
  119. // The CocoaPress shows the temperature for two
  120. // heating zones, but has no bed temperature
  121. cmd.font(font_large);
  122. if (!isHeaterIdle(E0) && getTargetTemp_celsius(E0) > 0)
  123. format_temp_and_temp(str, getActualTemp_celsius(E0), getTargetTemp_celsius(E0));
  124. else
  125. format_temp_and_idle(str, getActualTemp_celsius(E0));
  126. ui.bounds(POLY(zone1_temp), x, y, h, v);
  127. cmd.text(x, y, h, v, str);
  128. if (!isHeaterIdle(E1) && getTargetTemp_celsius(E1) > 0)
  129. format_temp_and_temp(str, getActualTemp_celsius(E1), getTargetTemp_celsius(E1));
  130. else
  131. format_temp_and_idle(str, getActualTemp_celsius(E1));
  132. ui.bounds(POLY(zone2_temp), x, y, h, v);
  133. cmd.text(x, y, h, v, str);
  134. #endif
  135. }
  136. }
  137. void StatusScreen::draw_syringe(draw_mode_t what) {
  138. int16_t x, y, h, v;
  139. #ifdef E_MAX_POS
  140. const float fill_level = 1.0 - min(1.0, max(0.0, getAxisPosition_mm(E0) / E_MAX_POS));
  141. #else
  142. const float fill_level = 0.75;
  143. #endif
  144. const bool e_homed = (true
  145. #if ENABLED(TOUCH_UI_LULZBOT_BIO)
  146. && isAxisPositionKnown(E0)
  147. #endif
  148. );
  149. CommandProcessor cmd;
  150. PolyUI ui(cmd, what);
  151. if (what & BACKGROUND) {
  152. // Paint the shadow for the syringe
  153. ui.color(shadow_rgb);
  154. ui.shadow(POLY(syringe_outline), shadow_depth);
  155. }
  156. if (what & FOREGROUND && e_homed) {
  157. // Paint the syringe icon
  158. ui.color(syringe_rgb);
  159. ui.fill(POLY(syringe_outline));
  160. ui.color(fill_rgb);
  161. ui.bounds(POLY(syringe_fluid), x, y, h, v);
  162. cmd.cmd(SAVE_CONTEXT());
  163. cmd.cmd(SCISSOR_XY(x,y + v * (1.0 - fill_level)));
  164. cmd.cmd(SCISSOR_SIZE(h, v * fill_level));
  165. ui.fill(POLY(syringe_fluid), false);
  166. cmd.cmd(RESTORE_CONTEXT());
  167. ui.color(stroke_rgb);
  168. ui.fill(POLY(syringe));
  169. }
  170. }
  171. void StatusScreen::draw_arrows(draw_mode_t what) {
  172. const bool e_homed = (true
  173. #if ENABLED(TOUCH_UI_LULZBOT_BIO)
  174. && isAxisPositionKnown(E0)
  175. #endif
  176. );
  177. const bool z_homed = isAxisPositionKnown(Z);
  178. CommandProcessor cmd;
  179. PolyUI ui(cmd, what);
  180. ui.button_fill (fill_rgb);
  181. ui.button_stroke(stroke_rgb, 28);
  182. ui.button_shadow(shadow_rgb, shadow_depth);
  183. if ((what & BACKGROUND) || jog_xy) {
  184. ui.button(1, POLY(x_neg));
  185. ui.button(2, POLY(x_pos));
  186. ui.button(3, POLY(y_neg));
  187. ui.button(4, POLY(y_pos));
  188. }
  189. if ((what & BACKGROUND) || z_homed) {
  190. ui.button(5, POLY(z_neg));
  191. ui.button(6, POLY(z_pos));
  192. }
  193. if ((what & BACKGROUND) || e_homed) {
  194. ui.button(7, POLY(e_neg));
  195. ui.button(8, POLY(e_pos));
  196. }
  197. }
  198. void StatusScreen::draw_fine_motion(draw_mode_t what) {
  199. int16_t x, y, h, v;
  200. CommandProcessor cmd;
  201. PolyUI ui(cmd, what);
  202. cmd.font(
  203. #ifdef TOUCH_UI_PORTRAIT
  204. font_medium
  205. #else
  206. font_small
  207. #endif
  208. )
  209. .tag(16);
  210. if (what & BACKGROUND) {
  211. ui.bounds(POLY(fine_label), x, y, h, v);
  212. cmd.cmd(COLOR_RGB(bg_text_enabled))
  213. .text(x, y, h, v, GET_TEXT_F(MSG_FINE_MOTION));
  214. }
  215. if (what & FOREGROUND) {
  216. ui.bounds(POLY(fine_toggle), x, y, h, v);
  217. cmd.colors(ui_toggle)
  218. .toggle2(x, y, h, v, GET_TEXT_F(MSG_NO), GET_TEXT_F(MSG_YES), fine_motion);
  219. }
  220. }
  221. void StatusScreen::draw_overlay_icons(draw_mode_t what) {
  222. const bool e_homed = (true
  223. #if ENABLED(TOUCH_UI_LULZBOT_BIO)
  224. && isAxisPositionKnown(E0)
  225. #endif
  226. );
  227. const bool z_homed = isAxisPositionKnown(Z);
  228. CommandProcessor cmd;
  229. PolyUI ui(cmd, what);
  230. if (what & FOREGROUND) {
  231. ui.button_fill (fill_rgb);
  232. ui.button_stroke(stroke_rgb, 28);
  233. ui.button_shadow(shadow_rgb, shadow_depth);
  234. if (!jog_xy) ui.button(12, POLY(padlock));
  235. if (!e_homed) ui.button(13, POLY(home_e));
  236. if (!z_homed) ui.button(14, POLY(home_z));
  237. }
  238. }
  239. void StatusScreen::draw_buttons(draw_mode_t what) {
  240. int16_t x, y, h, v;
  241. const bool has_media = isMediaInserted() && !isPrintingFromMedia();
  242. CommandProcessor cmd;
  243. PolyUI ui(cmd, what);
  244. ui.bounds(POLY(usb_btn), x, y, h, v);
  245. cmd.font(font_medium)
  246. .colors(normal_btn)
  247. .enabled(has_media)
  248. .colors(has_media ? action_btn : normal_btn)
  249. .tag(9).button(x, y, h, v,
  250. isPrintingFromMedia() ?
  251. GET_TEXT_F(MSG_PRINTING) :
  252. GET_TEXT_F(MSG_BUTTON_MEDIA)
  253. );
  254. ui.bounds(POLY(menu_btn), x, y, h, v);
  255. cmd.colors(!has_media ? action_btn : normal_btn).tag(10).button(x, y, h, v, GET_TEXT_F(MSG_BUTTON_MENU));
  256. }
  257. void StatusScreen::loadBitmaps() {
  258. // Load the bitmaps for the status screen
  259. constexpr uint32_t base = ftdi_memory_map::RAM_G;
  260. CLCD::mem_write_pgm(base + Bed_Heat_Icon_Info.RAMG_offset, Bed_Heat_Icon, sizeof(Bed_Heat_Icon));
  261. // Load fonts for internationalization
  262. #ifdef TOUCH_UI_USE_UTF8
  263. load_utf8_data(base + UTF8_FONT_OFFSET);
  264. #endif
  265. }
  266. void StatusScreen::onRedraw(draw_mode_t what) {
  267. if (what & BACKGROUND) {
  268. CommandProcessor cmd;
  269. cmd.cmd(CLEAR_COLOR_RGB(bg_color))
  270. .cmd(CLEAR(true,true,true))
  271. .tag(0);
  272. }
  273. draw_syringe(what);
  274. draw_temperature(what);
  275. draw_arrows(what);
  276. draw_overlay_icons(what);
  277. draw_buttons(what);
  278. draw_fine_motion(what);
  279. }
  280. bool StatusScreen::onTouchStart(uint8_t) {
  281. increment = 0;
  282. return true;
  283. }
  284. bool StatusScreen::onTouchEnd(uint8_t tag) {
  285. switch (tag) {
  286. case 1:
  287. case 2:
  288. case 3:
  289. case 4:
  290. case 12:
  291. if (!jog_xy) {
  292. jog_xy = true;
  293. injectCommands_P(PSTR("M17"));
  294. }
  295. jog({ 0, 0, 0 });
  296. break;
  297. case 5:
  298. case 6:
  299. jog({ 0, 0, 0 });
  300. break;
  301. case 9: GOTO_SCREEN(FilesScreen); break;
  302. case 10: GOTO_SCREEN(MainMenu); break;
  303. #if ENABLED(TOUCH_UI_LULZBOT_BIO)
  304. case 13: GOTO_SCREEN(BioConfirmHomeE); break;
  305. #endif
  306. case 14: SpinnerDialogBox::enqueueAndWait_P(F("G28 Z")); break;
  307. case 15: GOTO_SCREEN(TemperatureScreen); break;
  308. case 16: fine_motion = !fine_motion; break;
  309. default: return false;
  310. }
  311. // If a passcode is enabled, the LockScreen will prevent the
  312. // user from proceeding.
  313. LockScreen::check_passcode();
  314. return true;
  315. }
  316. bool StatusScreen::onTouchHeld(uint8_t tag) {
  317. if (tag >= 1 && tag <= 4 && !jog_xy) return false;
  318. const float s = min_speed + (fine_motion ? 0 : (max_speed - min_speed) * sq(increment));
  319. switch (tag) {
  320. case 1: jog({-s, 0, 0}); break;
  321. case 2: jog({ s, 0, 0}); break;
  322. case 4: jog({ 0, -s, 0}); break; // NOTE: Y directions inverted because bed rather than needle moves
  323. case 3: jog({ 0, s, 0}); break;
  324. case 5: jog({ 0, 0, -s}); break;
  325. case 6: jog({ 0, 0, s}); break;
  326. case 7: case 8:
  327. {
  328. if (ExtUI::isMoving()) return false;
  329. const feedRate_t feedrate = emin_speed + (fine_motion ? 0 : (emax_speed - emin_speed) * sq(increment));
  330. const float increment = 0.25 * feedrate * (tag == 7 ? -1 : 1);
  331. MoveAxisScreen::setManualFeedrate(E0, feedrate);
  332. UI_INCREMENT(AxisPosition_mm, E0);
  333. current_screen.onRefresh();
  334. break;
  335. }
  336. default:
  337. return false;
  338. }
  339. increment = min(1.0f, increment + 0.1f);
  340. return false;
  341. }
  342. void StatusScreen::setStatusMessage(progmem_str pstr) {
  343. #ifdef TOUCH_UI_LULZBOT_BIO
  344. BioPrintingDialogBox::setStatusMessage(pstr);
  345. #else
  346. UNUSED(pstr);
  347. #endif
  348. }
  349. void StatusScreen::setStatusMessage(const char * const str) {
  350. #ifdef TOUCH_UI_LULZBOT_BIO
  351. BioPrintingDialogBox::setStatusMessage(str);
  352. #else
  353. UNUSED(str);
  354. #endif
  355. }
  356. void StatusScreen::onIdle() {
  357. reset_menu_timeout();
  358. if (refresh_timer.elapsed(STATUS_UPDATE_INTERVAL)) {
  359. if (!EventLoop::is_touch_held())
  360. onRefresh();
  361. #ifdef TOUCH_UI_LULZBOT_BIO
  362. if (isPrintingFromMedia())
  363. BioPrintingDialogBox::show();
  364. #endif
  365. refresh_timer.start();
  366. }
  367. }
  368. #endif // TOUCH_UI_FTDI_EVE