cleanup all libs/ headers and dependent files
[clinton/Smoothieware.git] / src / modules / utils / panel / Panel.cpp
CommitLineData
399cb110 1/*
35089dc7
JM
2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4 Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
399cb110 5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
35089dc7
JM
6*/
7
8#include "libs/Kernel.h"
9#include "Panel.h"
ca6effd7
JM
10#include "PanelScreen.h"
11
35089dc7
JM
12#include "libs/nuts_bolts.h"
13#include "libs/utils.h"
35089dc7 14#include "Button.h"
ca6effd7 15
35089dc7 16#include "modules/utils/player/PlayerPublicAccess.h"
ca6effd7
JM
17#include "screens/CustomScreen.h"
18#include "screens/MainMenuScreen.h"
61134a65
JM
19#include "SlowTicker.h"
20#include "Gcode.h"
21#include "Pauser.h"
22#include "PublicData.h"
35089dc7
JM
23
24#include "panels/I2CLCD.h"
25#include "panels/VikiLCD.h"
1c2b594a 26#include "panels/Smoothiepanel.h"
357d0eda 27#include "panels/ReprapDiscountGLCD.h"
84e7fd5a 28#include "panels/ST7565.h"
f140cf3a 29#include "version.h"
7af0714f 30#include "checksumm.h"
8d54c34c 31#include "ConfigValue.h"
35089dc7 32
ca6effd7
JM
33#define panel_checksum CHECKSUM("panel")
34#define enable_checksum CHECKSUM("enable")
35#define lcd_checksum CHECKSUM("lcd")
36#define i2c_lcd_checksum CHECKSUM("i2c_lcd")
37#define viki_lcd_checksum CHECKSUM("viki_lcd")
38#define smoothiepanel_checksum CHECKSUM("smoothiepanel")
39#define panelolu2_checksum CHECKSUM("panelolu2")
40#define rrd_glcd_checksum CHECKSUM("reprap_discount_glcd")
41#define st7565_glcd_checksum CHECKSUM("st7565_glcd")
42
fa3f7b30
JM
43#define menu_offset_checksum CHECKSUM("menu_offset")
44#define encoder_resolution_checksum CHECKSUM("encoder_resolution")
45#define jog_x_feedrate_checksum CHECKSUM("alpha_jog_feedrate")
46#define jog_y_feedrate_checksum CHECKSUM("beta_jog_feedrate")
47#define jog_z_feedrate_checksum CHECKSUM("gamma_jog_feedrate")
f1e696a3 48#define longpress_delay_checksum CHECKSUM("longpress_delay")
ca6effd7
JM
49
50#define hotend_temp_checksum CHECKSUM("hotend_temperature")
51#define bed_temp_checksum CHECKSUM("bed_temperature")
52
862fc625
JM
53Panel::Panel()
54{
35089dc7
JM
55 this->counter_changed = false;
56 this->click_changed = false;
57 this->refresh_flag = false;
58 this->enter_menu_mode();
862fc625 59 this->lcd = NULL;
58d6d841 60 this->do_buttons = false;
862fc625
JM
61 this->idle_time = 0;
62 this->start_up = true;
63 this->current_screen = NULL;
7aa9fef3 64 strcpy(this->playing_file, "Playing file");
35089dc7
JM
65}
66
862fc625
JM
67Panel::~Panel()
68{
58d6d841 69 delete this->lcd;
35089dc7
JM
70}
71
862fc625
JM
72void Panel::on_module_loaded()
73{
35089dc7 74 // Exit if this module is not enabled
314ab8f7 75 if ( !THEKERNEL->config->value( panel_checksum, enable_checksum )->by_default(false)->as_bool() ) {
58d6d841
JM
76 delete this;
77 return;
399cb110 78 }
35089dc7 79
58d6d841
JM
80 // Initialise the LCD, see which LCD to use
81 if (this->lcd != NULL) delete this->lcd;
314ab8f7 82 int lcd_cksm = get_checksum(THEKERNEL->config->value(panel_checksum, lcd_checksum)->by_default("i2c")->as_string());
58d6d841
JM
83
84 // Note checksums are not const expressions when in debug mode, so don't use switch
862fc625 85 if (lcd_cksm == i2c_lcd_checksum) {
58d6d841 86 this->lcd = new I2CLCD();
862fc625 87 } else if (lcd_cksm == viki_lcd_checksum) {
58d6d841 88 this->lcd = new VikiLCD();
e0107f6b 89 this->lcd->set_variant(0);
862fc625 90 } else if (lcd_cksm == panelolu2_checksum) {
e0107f6b
JM
91 this->lcd = new VikiLCD();
92 this->lcd->set_variant(1);
862fc625 93 } else if (lcd_cksm == smoothiepanel_checksum) {
1c2b594a 94 this->lcd = new Smoothiepanel();
862fc625 95 } else if (lcd_cksm == rrd_glcd_checksum) {
357d0eda 96 this->lcd = new ReprapDiscountGLCD();
862fc625 97 } else if (lcd_cksm == st7565_glcd_checksum) {
84e7fd5a 98 this->lcd = new ST7565();
862fc625 99 } else {
58d6d841
JM
100 // no lcd type defined
101 return;
102 }
103
ca6effd7
JM
104 this->custom_screen= new CustomScreen(); // this needs to be called here as it needs the config cache loaded
105
58d6d841
JM
106 // some panels may need access to this global info
107 this->lcd->setPanel(this);
108
f65ce58f 109 // the number of screen lines the panel supports
862fc625 110 this->screen_lines = this->lcd->get_screen_lines();
399cb110 111
19fb4629
JM
112 // some encoders may need more clicks to move menu, this is a divisor and is in config as it is
113 // an end user usability issue
314ab8f7 114 this->menu_offset = THEKERNEL->config->value( panel_checksum, menu_offset_checksum )->by_default(0)->as_number();
19fb4629 115
fa3f7b30 116 // override default encoder resolution if needed
314ab8f7 117 this->encoder_click_resolution = THEKERNEL->config->value( panel_checksum, encoder_resolution_checksum )->by_default(this->lcd->getEncoderResolution())->as_number();
fa3f7b30 118
58d6d841 119 // load jogging feedrates in mm/min
1ad23cd3
MM
120 jogging_speed_mm_min[0] = THEKERNEL->config->value( panel_checksum, jog_x_feedrate_checksum )->by_default(3000.0f)->as_number();
121 jogging_speed_mm_min[1] = THEKERNEL->config->value( panel_checksum, jog_y_feedrate_checksum )->by_default(3000.0f)->as_number();
122 jogging_speed_mm_min[2] = THEKERNEL->config->value( panel_checksum, jog_z_feedrate_checksum )->by_default(300.0f )->as_number();
f19a841a
JM
123
124 // load the default preset temeratures
1ad23cd3
MM
125 default_hotend_temperature = THEKERNEL->config->value( panel_checksum, hotend_temp_checksum )->by_default(185.0f )->as_number();
126 default_bed_temperature = THEKERNEL->config->value( panel_checksum, bed_temp_checksum )->by_default(60.0f )->as_number();
f19a841a 127
399cb110 128
95195a29
JM
129 this->up_button.up_attach( this, &Panel::on_up );
130 this->down_button.up_attach( this, &Panel::on_down );
ab4abea9 131 this->click_button.up_attach( this, &Panel::on_select );
95195a29 132 this->back_button.up_attach( this, &Panel::on_back );
52500e58 133 this->pause_button.up_attach( this, &Panel::on_pause );
35089dc7 134
355c5796
L
135
136 //setting longpress_delay
137 int longpress_delay = THEKERNEL->config->value( panel_checksum, longpress_delay_checksum )->by_default(0)->as_number();
138 this->up_button.set_longpress_delay(longpress_delay);
f1e696a3 139 this->down_button.set_longpress_delay(longpress_delay);
355c5796
L
140// this->click_button.set_longpress_delay(longpress_delay);
141// this->back_button.set_longpress_delay(longpress_delay);
142// this->pause_button.set_longpress_delay(longpress_delay);
61134a65
JM
143
144
314ab8f7
MM
145 THEKERNEL->slow_ticker->attach( 100, this, &Panel::button_tick );
146 THEKERNEL->slow_ticker->attach( 1000, this, &Panel::encoder_check );
399cb110 147
767e7c51
JM
148 // Register for events
149 this->register_for_event(ON_IDLE);
150 this->register_for_event(ON_MAIN_LOOP);
399cb110 151 this->register_for_event(ON_GCODE_RECEIVED);
767e7c51 152
35089dc7 153 // Refresh timer
314ab8f7 154 THEKERNEL->slow_ticker->attach( 20, this, &Panel::refresh_tick );
35089dc7
JM
155}
156
157// Enter a screen, we only care about it now
862fc625
JM
158void Panel::enter_screen(PanelScreen *screen)
159{
35089dc7
JM
160 screen->panel = this;
161 this->current_screen = screen;
162 this->reset_counter();
163 this->current_screen->on_enter();
164}
165
166// Reset the counter
862fc625
JM
167void Panel::reset_counter()
168{
35089dc7
JM
169 *this->counter = 0;
170 this->counter_changed = false;
171}
172
173// Indicate the idle loop we want to call the refresh hook in the current screen
5ff3e912 174// called 20 times a second
862fc625
JM
175uint32_t Panel::refresh_tick(uint32_t dummy)
176{
58d6d841
JM
177 this->refresh_flag = true;
178 this->idle_time++;
179 return 0;
35089dc7
JM
180}
181
446deda2 182// Encoder pins changed in interrupt
862fc625
JM
183uint32_t Panel::encoder_check(uint32_t dummy)
184{
58d6d841
JM
185 // TODO if encoder reads go through i2c like on smoothie panel this needs to be
186 // optionally done in idle loop, however when reading encoder directly it needs to be done
187 // frequently, smoothie panel will return an actual delta count so won't miss any if polled slowly
b6e81799 188 // NOTE this code will not work if change is not -1,0,-1 anything greater (as in above case) will not work properly
58d6d841 189 static int encoder_counter = 0;
35089dc7 190 int change = lcd->readEncoderDelta();
58d6d841 191 encoder_counter += change;
b6e81799 192
862fc625 193 if ( change != 0 && encoder_counter % this->encoder_click_resolution == 0 ) {
58d6d841
JM
194 this->counter_changed = true;
195 (*this->counter) += change;
862fc625 196 this->idle_time = 0;
35089dc7 197 }
58d6d841 198 return 0;
35089dc7
JM
199}
200
201// Read and update each button
862fc625
JM
202uint32_t Panel::button_tick(uint32_t dummy)
203{
58d6d841
JM
204 this->do_buttons = true;
205 return 0;
35089dc7
JM
206}
207
862fc625 208void Panel::on_gcode_received(void *argument)
399cb110 209{
862fc625
JM
210 Gcode *gcode = static_cast<Gcode *>(argument);
211 if ( gcode->has_m) {
212 if ( gcode->m == 117 ) { // set LCD message
213 this->message = get_arguments(gcode->command);
214 if (this->message.size() > 20) this->message = this->message.substr(0, 20);
399cb110
JM
215 gcode->mark_as_taken();
216 }
217 }
218}
219
35089dc7 220// on main loop, we can send gcodes or do anything that waits in this loop
862fc625
JM
221void Panel::on_main_loop(void *argument)
222{
223 if (this->current_screen != NULL) {
f140cf3a
JM
224 this->current_screen->on_main_loop();
225 this->lcd->on_main_loop();
226 }
35089dc7
JM
227}
228
c96fd70a
JM
229
230#define ohw_logo_antipixel_width 80
231#define ohw_logo_antipixel_height 15
161164be 232static const uint8_t ohw_logo_antipixel_bits[] = {
862fc625
JM
233 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
234 0x00, 0x00, 0x00, 0x01, 0x80, 0x0C, 0x00, 0x33, 0x18, 0xBB, 0xFF, 0xFF, 0xFF, 0xFD, 0x80, 0x5E,
235 0x80, 0x2D, 0x6B, 0x9B, 0xFF, 0xFF, 0xFF, 0xFD, 0x80, 0xFF, 0xC0, 0x2D, 0x18, 0xAB, 0xFF, 0xFF,
236 0xFF, 0xFD, 0x80, 0xFF, 0xC0, 0x2D, 0x7B, 0xB3, 0xFF, 0xFF, 0xFF, 0xFD, 0x80, 0x7F, 0x80, 0x33,
237 0x78, 0xBB, 0xFF, 0xFF, 0xFF, 0xFD, 0x81, 0xF3, 0xE0, 0x3F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD,
238 0x81, 0xF3, 0xE0, 0x3F, 0xFD, 0xB3, 0x18, 0xDD, 0x98, 0xC5, 0x81, 0xF3, 0xE0, 0x3F, 0xFD, 0xAD,
239 0x6B, 0x5D, 0x6B, 0x5D, 0x80, 0x73, 0x80, 0x3F, 0xFC, 0x21, 0x1B, 0x55, 0x08, 0xC5, 0x80, 0xF3,
240 0xC0, 0x3F, 0xFD, 0xAD, 0x5B, 0x49, 0x6A, 0xDD, 0x80, 0xE1, 0xC0, 0x3F, 0xFD, 0xAD, 0x68, 0xDD,
241 0x6B, 0x45, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF,
242 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
c96fd70a
JM
243};
244
35089dc7
JM
245// On idle things, we don't want to do shit in interrupts
246// don't queue gcodes in this
862fc625
JM
247void Panel::on_idle(void *argument)
248{
249 if (this->start_up) {
f140cf3a
JM
250 this->lcd->init();
251
ebc64506
JM
252 Version v;
253 string build(v.get_build());
254 string date(v.get_build_date());
255 this->lcd->clear();
862fc625
JM
256 this->lcd->setCursor(0, 0); this->lcd->printf("Welcome to Smoothie");
257 this->lcd->setCursor(0, 1); this->lcd->printf("%s", build.substr(0, 20).c_str());
258 this->lcd->setCursor(0, 2); this->lcd->printf("%s", date.substr(0, 20).c_str());
259 this->lcd->setCursor(0, 3); this->lcd->printf("Please wait....");
ebc64506 260
862fc625 261 if (this->lcd->hasGraphics()) {
c96fd70a
JM
262 this->lcd->bltGlyph(24, 40, ohw_logo_antipixel_width, ohw_logo_antipixel_height, ohw_logo_antipixel_bits);
263 }
264
f54d25cb
JM
265 this->lcd->on_refresh(true); // tell lcd to display now
266
f140cf3a 267 // Default top screen
ca6effd7 268 this->top_screen= new MainMenuScreen();
f140cf3a 269 this->top_screen->set_panel(this);
ca6effd7 270 this->custom_screen->set_parent(this->top_screen);
862fc625 271 this->start_up = false;
5ff3e912 272 return;
f140cf3a 273 }
35089dc7 274
ca6effd7 275 MainMenuScreen *mms= static_cast<MainMenuScreen*>(this->top_screen);
58d6d841 276 // after being idle for a while switch to Watch screen
5ff3e912 277 if (this->current_screen != NULL && this->idle_time > this->current_screen->idle_timeout_secs()*20) {
862fc625 278 this->idle_time = 0;
ca6effd7
JM
279 if (mms->watch_screen != this->current_screen) {
280 this->enter_screen(mms->watch_screen);
58d6d841
JM
281 // TODO do we need to reset any state?
282 }
399cb110 283
58d6d841
JM
284 return;
285 }
399cb110 286
5ff3e912
JM
287 if(current_screen == NULL && this->idle_time > 20*4) {
288 this->enter_screen(mms->watch_screen);
289 return;
290 }
291
862fc625 292 if (this->do_buttons) {
58d6d841
JM
293 // we don't want to do I2C in interrupt mode
294 this->do_buttons = false;
295
296 // read the actual buttons
862fc625
JM
297 int but = lcd->readButtons();
298 if (but != 0) {
299 this->idle_time = 0;
5ff3e912
JM
300 if(current_screen == NULL) {
301 // we were in startup screen so go to watch screen
302 this->enter_screen(mms->watch_screen);
303 return;
304 }
f140cf3a
JM
305 }
306
58d6d841 307 // fire events if the buttons are active and debounce is satisfied
862fc625
JM
308 this->up_button.check_signal(but & BUTTON_UP);
309 this->down_button.check_signal(but & BUTTON_DOWN);
310 this->back_button.check_signal(but & BUTTON_LEFT);
311 this->click_button.check_signal(but & BUTTON_SELECT);
312 this->pause_button.check_signal(but & BUTTON_PAUSE);
313 }
399cb110 314
35089dc7 315 // If we are in menu mode and the position has changed
862fc625 316 if ( this->mode == MENU_MODE && this->counter_change() ) {
35089dc7
JM
317 this->menu_update();
318 }
319
320 // If we are in control mode
862fc625 321 if ( this->mode == CONTROL_MODE && this->counter_change() ) {
58d6d841 322 this->control_value_update();
35089dc7
JM
323 }
324
325 // If we must refresh
862fc625 326 if ( this->refresh_flag ) {
35089dc7 327 this->refresh_flag = false;
862fc625 328 if (this->current_screen != NULL) {
f140cf3a
JM
329 this->current_screen->on_refresh();
330 this->lcd->on_refresh();
331 }
35089dc7
JM
332 }
333}
334
335// Hooks for button clicks
862fc625
JM
336uint32_t Panel::on_up(uint32_t dummy)
337{
25121d12 338 // this is simulating encoder clicks, but needs to be inverted to
b6e81799
JM
339 // increment values on up,increment by
340 int inc = (this->mode == CONTROL_MODE) ? 1 : -(this->menu_offset+1);
25121d12 341 *this->counter += inc;
58d6d841
JM
342 this->counter_changed = true;
343 return 0;
35089dc7 344}
5ff3e912 345
862fc625
JM
346uint32_t Panel::on_down(uint32_t dummy)
347{
b6e81799 348 int inc = (this->mode == CONTROL_MODE) ? -1 : (this->menu_offset+1);
25121d12 349 *this->counter += inc;
58d6d841
JM
350 this->counter_changed = true;
351 return 0;
35089dc7
JM
352}
353
354// on most menu screens will go back to previous higher menu
862fc625
JM
355uint32_t Panel::on_back(uint32_t dummy)
356{
357 if (this->mode == MENU_MODE && this->current_screen != NULL && this->current_screen->parent != NULL) {
58d6d841
JM
358 this->enter_screen(this->current_screen->parent);
359 }
360 return 0;
35089dc7
JM
361}
362
862fc625
JM
363uint32_t Panel::on_select(uint32_t dummy)
364{
58d6d841
JM
365 // TODO make configurable, including turning off
366 // buzz is ignored on panels that do not support buzz
58d6d841 367 this->click_changed = true;
862fc625
JM
368 this->idle_time = 0;
369 lcd->buzz(60, 300); // 50ms 300Hz
58d6d841 370 return 0;
35089dc7
JM
371}
372
862fc625
JM
373uint32_t Panel::on_pause(uint32_t dummy)
374{
375 if (!paused) {
52500e58 376 THEKERNEL->pauser->take();
862fc625
JM
377 paused = true;
378 } else {
52500e58 379 THEKERNEL->pauser->release();
862fc625 380 paused = false;
52500e58
L
381 }
382 return 0;
383}
384
862fc625
JM
385bool Panel::counter_change()
386{
387 if ( this->counter_changed ) {
388 this->counter_changed = false;
389 return true;
390 } else {
391 return false;
392 }
393}
394bool Panel::click()
395{
396 if ( this->click_changed ) {
397 this->click_changed = false;
398 return true;
399 } else {
400 return false;
401 }
402}
35089dc7
JM
403
404
405// Enter menu mode
862fc625
JM
406void Panel::enter_menu_mode()
407{
35089dc7
JM
408 this->mode = MENU_MODE;
409 this->counter = &this->menu_selected_line;
410 this->menu_changed = false;
411}
412
862fc625
JM
413void Panel::setup_menu(uint16_t rows)
414{
f65ce58f
JM
415 this->setup_menu(rows, min(rows, this->max_screen_lines()));
416}
417
862fc625
JM
418void Panel::setup_menu(uint16_t rows, uint16_t lines)
419{
35089dc7 420 this->menu_selected_line = 0;
862fc625 421 this->menu_current_line = 0;
399cb110 422 this->menu_start_line = 0;
35089dc7 423 this->menu_rows = rows;
206167cf 424 this->panel_lines = lines;
35089dc7
JM
425}
426
862fc625
JM
427void Panel::menu_update()
428{
399cb110 429 // Limits, up and down
446deda2 430 // NOTE menu_selected_line is changed in an interrupt and can change at any time
862fc625 431 int msl = this->menu_selected_line; // hopefully this is atomic
206167cf
JM
432
433 #if 0
434 // this allows it to wrap but with new method we dont; want to wrap
862fc625
JM
435 msl = msl % ( this->menu_rows << this->menu_offset );
436 while ( msl < 0 ) {
437 msl += this->menu_rows << this->menu_offset;
438 }
206167cf
JM
439 #else
440 // limit selected line to screen lines available
441 if(msl >= this->menu_rows<<this->menu_offset){
442 msl= (this->menu_rows-1)<<this->menu_offset;
443 }else if(msl < 0) msl= 0;
444 #endif
446deda2 445
206167cf 446 this->menu_selected_line = msl; // update atomically we hope
b6e81799
JM
447 // figure out which actual line to select, if we have a menu offset it means we want to move one line per two clicks
448 if(msl % (this->menu_offset+1) == 0) { // only if divisible by offset
449 this->menu_current_line = msl >> this->menu_offset;
450 }
35089dc7
JM
451
452 // What to display
206167cf
JM
453 if ( this->menu_rows > this->panel_lines ) {
454 #if 0
455 // old way of scrolling not nice....
862fc625 456 if ( this->menu_current_line >= 2 ) {
446deda2 457 this->menu_start_line = this->menu_current_line - 1;
35089dc7 458 }
206167cf
JM
459 if ( this->menu_current_line > this->menu_rows - this->panel_lines ) {
460 this->menu_start_line = this->menu_rows - this->panel_lines;
461 }
462 #else
463 // new way we only scroll the lines when the cursor hits the bottom of the screen or the top of the screen
464 // do we want to scroll up?
465 int sl= this->menu_current_line - this->menu_start_line; // screen line we are on
466 if(sl >= this->panel_lines) {
467 this->menu_start_line += ((sl+1)-this->panel_lines); // scroll up to keep it on the screen
468
469 }else if(sl < 0 ) { // do we want to scroll down?
470 this->menu_start_line += sl; // scroll down
35089dc7 471 }
206167cf
JM
472 #endif
473
474 }else{
475 this->menu_start_line = 0;
35089dc7
JM
476 }
477
478 this->menu_changed = true;
479}
480
862fc625
JM
481bool Panel::menu_change()
482{
483 if ( this->menu_changed ) {
484 this->menu_changed = false;
485 return true;
486 } else {
487 return false;
488 }
35089dc7
JM
489}
490
862fc625
JM
491bool Panel::control_value_change()
492{
493 if ( this->control_value_changed ) {
494 this->control_value_changed = false;
495 return true;
496 } else {
497 return false;
498 }
35089dc7
JM
499}
500
1ad23cd3 501bool Panel::enter_control_mode(float passed_normal_increment, float passed_pressed_increment)
862fc625 502{
35089dc7
JM
503 this->mode = CONTROL_MODE;
504 this->normal_increment = passed_normal_increment;
35089dc7
JM
505 this->counter = &this->control_normal_counter;
506 this->control_normal_counter = 0;
58d6d841
JM
507 this->control_base_value = 0;
508 return true;
35089dc7
JM
509}
510
862fc625
JM
511void Panel::control_value_update()
512{
58d6d841
JM
513 // TODO what do we do here?
514 this->control_value_changed = true;
35089dc7
JM
515}
516
1ad23cd3 517void Panel::set_control_value(float value)
862fc625 518{
58d6d841 519 this->control_base_value = value;
35089dc7
JM
520}
521
1ad23cd3 522float Panel::get_control_value()
862fc625
JM
523{
524 return this->control_base_value + (this->control_normal_counter * this->normal_increment);
35089dc7
JM
525}
526
862fc625
JM
527bool Panel::is_playing() const
528{
58d6d841
JM
529 void *returned_data;
530
862fc625
JM
531 bool ok = THEKERNEL->public_data->get_value( player_checksum, is_playing_checksum, &returned_data );
532 if (ok) {
533 bool b = *static_cast<bool *>(returned_data);
58d6d841
JM
534 return b;
535 }
536 return false;
7aa9fef3
JM
537}
538
862fc625
JM
539void Panel::set_playing_file(string f)
540{
7aa9fef3 541 // just copy the first 20 characters after the first / if there
862fc625
JM
542 size_t n = f.find_last_of('/');
543 if (n == string::npos) n = 0;
544 strncpy(playing_file, f.substr(n + 1, 19).c_str(), sizeof(playing_file));
545 playing_file[sizeof(playing_file) - 1] = 0;
7aa9fef3 546}