C--
Posted: 14 Oct 2019, 17:12
Il me semble que programmer la Numworks est difficile, en tout cas pour moi qui n'aime pas les hierarchies de classe du C++ et qui ai l'habitude de travailler avec emacs et des gros fichiers sans arborescence et pas avec un gros IDE.
Je poste ici quelques routines que j'ai eu beaucoup de mal a rassembler, qui j'espere faciliteront le travail a d'autres. Tout cela est base sur le firmware 11.
Le 1er point a resoudre est avoir un point d'entree depuis l'OS. Je pense que la frappe de la touche Home depuis Home est un bon point d'entree. Pour cela ajouter dans apps/home/controler.cpp
J'ai ajoute des fonctions dans python/port.cpp pour attendre une touche (getKey) et gerer la ligne d'etat.
Il faudra un peu les modifier pour un autre usage que dans KhiCAS.
Pour les traces, j'ai ajoute dans modkandinsky.cpp
Le fichier kdisplay.h de giac-1.5.0 contient les declarations correspondantes, celle des touches (tres inspire du clavier Casio), ainsi que des fonctions d'UI, en particulier des menus a choix et un widget editeur de programmes, tout ca etant accessible sur le firmware delta+giac-1.5.0.
Je poste ici quelques routines que j'ai eu beaucoup de mal a rassembler, qui j'espere faciliteront le travail a d'autres. Tout cela est base sur le firmware 11.
Le 1er point a resoudre est avoir un point d'entree depuis l'OS. Je pense que la frappe de la touche Home depuis Home est un bon point d'entree. Pour cela ajouter dans apps/home/controler.cpp
- Code: Select all
bool Controller::handleEvent(Ion::Events::Event event) {
if (event==Ion::Events::Home){
caseval("+"); // appeler ici votre programme
AppsContainer::sharedAppsContainer()->m_window.redraw(true);
return true;
}
...
}
J'ai ajoute des fonctions dans python/port.cpp pour attendre une touche (getKey) et gerer la ligne d'etat.
Il faudra un peu les modifier pour un autre usage que dans KhiCAS.
- Code: Select all
void statuslinemsg(const char * msg){
AppsContainer::sharedAppsContainer()->reloadTitleBarView();
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
if (ptr)
ptr->displaySandbox();
auto ctx=KDIonContext::sharedContext();
KDRect save=ctx->m_clippingRect;
KDPoint o=ctx->m_origin;
ctx->setClippingRect(KDRect(0,0,280,18));
ctx->setOrigin(KDPoint(0,0));
KDRect rect(0,0,280,18);
KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/);
if (strlen(msg)>25)
ctx->drawString(msg, KDPoint(0,0), KDFont::SmallFont, 0, 64934);
else
ctx->drawString(msg, KDPoint(0,0), KDFont::LargeFont, 0, 64934);
ctx->setClippingRect(save);
ctx->setOrigin(o);
}
void statusline(int mode){
AppsContainer::sharedAppsContainer()->reloadTitleBarView();
auto ctx=KDIonContext::sharedContext();
KDRect save=ctx->m_clippingRect;
KDPoint o=ctx->m_origin;
ctx->setClippingRect(KDRect(0,0,320,18));
ctx->setOrigin(KDPoint(0,0));
KDRect rect(0,0,mode==1?320:280,18);
KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/);
const char * text=0;
Poincare::Preferences * preferences = Poincare::Preferences::sharedPreferences();
if (preferences->angleUnit() == Poincare::Preferences::AngleUnit::Radian)
text="rad";
else
text="deg";
// ctx->drawString(text, KDPoint(5,1), KDFont::SmallFont, 0, 63488 /* Palette::Red*/);
ctx->drawString(text, KDPoint(5,1), KDFont::SmallFont, 0, 64934);
if (khicas_eval)
text="KHICAS";
else
text="PYTHON";
ctx->drawString(text, KDPoint(100,1), KDFont::SmallFont, 0, 64934);
text=" ";
if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::Shift)
text="shift ";
else {
if (Ion::Events::isAlphaActive()){
if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::AlphaLock)
text="alphal";
if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::ShiftAlphaLock)
text="ALPHAL";
if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::Alpha)
text="1alpha";
if (Ion::Events::shiftAlphaStatus()==Ion::Events::ShiftAlphaStatus::ShiftAlpha)
text="1ALPHA";
}
}
ctx->drawString(text, KDPoint(248,1), KDFont::SmallFont, 0, 64934 /* Palette::YellowDark*/);
if (mode==1){
if (Ion::USB::isPlugged())
text="charge";
else {
auto c=Ion::Battery::level();
if (c==Ion::Battery::Charge::EMPTY)
text="empty";
if (c==Ion::Battery::Charge::LOW)
text="low";
if (c==Ion::Battery::Charge::FULL)
text="full";
}
ctx->drawString(text, KDPoint(280,1), KDFont::SmallFont, 0, 64934 /* Palette::YellowDark*/);
}
ctx->setClippingRect(save);
ctx->setOrigin(o);
}
bool isalphaactive(){
return Ion::Events::isAlphaActive();
}
void lock_alpha(){
Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::AlphaLock);
statusline(0);
}
void reset_kbd(){
Ion::Events::setShiftAlphaStatus(Ion::Events::ShiftAlphaStatus::Default);
statusline(0);
}
void os_redraw(){
AppsContainer::sharedAppsContainer()->m_window.redraw(true);
}
bool alphawasactive=false;
int getkey_raw(bool allow_suspend){
int key=-1;
for (;;){
int timeout=10000;
alphawasactive=Ion::Events::isAlphaActive();
Ion::Events::Event event=Ion::Events::getEvent(&timeout);
auto ctx=KDIonContext::sharedContext();
KDRect save=ctx->m_clippingRect;
KDPoint o=ctx->m_origin;
ctx->setClippingRect(KDRect(0,0,320,240));
ctx->setOrigin(KDPoint(0,0));
KDRect rect(0,0,320,240);
if (event == Ion::Events::USBPlug) {
KDIonContext::sharedContext()->pushRectUniform(rect,33333);
if (Ion::USB::isPlugged()) {
if (GlobalPreferences::sharedGlobalPreferences()->examMode() == GlobalPreferences::ExamMode::Activate) {
Ion::LED::setColor(KDColorBlack);
Ion::LED::updateColorWithPlugAndCharge();
GlobalPreferences::sharedGlobalPreferences()->setExamMode(GlobalPreferences::ExamMode::Deactivate);
// displayExamModePopUp(false);
} else {
Ion::USB::enable();
}
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
} else {
Ion::USB::disable();
}
}
if (event == Ion::Events::USBEnumeration || event == Ion::Events::USBPlug || event == Ion::Events::BatteryCharging) {
Ion::LED::updateColorWithPlugAndCharge();
}
if (event == Ion::Events::USBEnumeration
) {
KDIonContext::sharedContext()->pushRectUniform(rect,64934 /* Palette::YellowDark*/);
if (Ion::USB::isPlugged()) {
/* Just after a software update, the battery timer does not have time to
* fire before the calculator enters DFU mode. As the DFU mode blocks the
* event loop, we update the battery state "manually" here.
* We do it before switching to USB application to redraw the battery
* pictogram. */
// updateBatteryState();
KDIonContext::sharedContext()->pushRectUniform(rect,65535);
Ion::USB::DFU();
KDIonContext::sharedContext()->pushRectUniform(rect,22222);
// Update LED when exiting DFU mode
Ion::LED::updateColorWithPlugAndCharge();
} else {
/* Sometimes, the device gets an ENUMDNE interrupts when being unplugged
* from a non-USB communicating host (e.g. a USB charger). The interrupt
* must me cleared: if not the next enumeration attempts will not be
* detected. */
Ion::USB::clearEnumerationInterrupt();
}
}
if (event.isKeyboardEvent()) {
// m_backlightDimmingTimer.reset();
// m_suspendTimer.reset();
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
}
ctx->setClippingRect(save);
ctx->setOrigin(o);
if (event==Ion::Events::Shift || event==Ion::Events::Alpha){
statusline();
continue;
}
if (event.isKeyboardEvent()){
key=event.id();
if (allow_suspend && (key==7 || key==8) ){ // power
Ion::Power::suspend(true);
Ion::Backlight::setBrightness(GlobalPreferences::sharedGlobalPreferences()->brightnessLevel());
AppsContainer::sharedAppsContainer()->reloadTitleBarView();
//AppsContainer::sharedAppsContainer()->redrawWindow();
statusline(1);
//continue;
}
else
statusline();
break;
}
}
return key;
}
const short int translated_keys[]=
{
// non shifted
KEY_CTRL_LEFT,KEY_CTRL_UP,KEY_CTRL_DOWN,KEY_CTRL_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT,
KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11,
KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,KEY_CTRL_XTT,KEY_CTRL_VARS,KEY_CTRL_CATALOG,KEY_CTRL_DEL,
KEY_CHAR_EXP,KEY_CHAR_LN,KEY_CHAR_LOG,KEY_CHAR_IMGNRY,',',KEY_CHAR_POW,
KEY_CHAR_SIN,KEY_CHAR_COS,KEY_CHAR_TAN,KEY_CHAR_PI,KEY_CHAR_ROOT,KEY_CHAR_SQUARE,
'7','8','9','(',')',-1,
'4','5','6','*','/',-1,
'1','2','3','+','-',-1,
'0','.',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1,
// shifted
KEY_SHIFT_LEFT,KEY_CTRL_PAGEUP,KEY_CTRL_PAGEDOWN,KEY_SHIFT_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT,
KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11,
KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,KEY_CTRL_CUT,KEY_CTRL_CLIP,KEY_CTRL_PASTE,KEY_CTRL_DEL,
KEY_CHAR_LBRCKT,KEY_CHAR_RBRCKT,KEY_CHAR_LBRACE,KEY_CHAR_RBRACE,'_',KEY_CHAR_STORE,
KEY_CHAR_ASIN,KEY_CHAR_ACOS,KEY_CHAR_ATAN,'=','<','>',
'7','8','9','(',')',-1,
'4','5','6',KEY_CHAR_FACTOR,'%',-1,
'1','2','3',KEY_CHAR_NORMAL,'\\',-1,
'0','.',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1,
// alpha
KEY_CTRL_LEFT,KEY_CTRL_UP,KEY_CTRL_DOWN,KEY_CTRL_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT,
KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11,
KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,':',';','"',KEY_CTRL_DEL,
'a','b','c','d','e','f',
'g','h','i','j','k','l',
'm','n','o','p','q',-1,
'r','s','t','u','v',-1,
'w','x','y','z',' ',-1,
'?','!',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1,
// alpha shifted
KEY_SHIFT_LEFT,KEY_CTRL_PAGEUP,KEY_CTRL_PAGEDOWN,KEY_SHIFT_RIGHT,KEY_CTRL_OK,KEY_CTRL_EXIT,
KEY_CTRL_MENU,KEY_PRGM_ACON,KEY_PRGM_ACON,9,10,11,
KEY_CTRL_SHIFT,KEY_CTRL_ALPHA,':',';','\'','%',
'A','B','C','D','E','F',
'G','H','I','J','K','L',
'M','N','O','P','Q',-1,
'R','S','T','U','V',-1,
'W','X','Y','Z',' ',-1,
'?','!',KEY_CHAR_EXPN10,KEY_CHAR_ANS,KEY_CTRL_EXE,-1,
};
int getkey(bool allow_suspend){
int k=getkey_raw(allow_suspend);
// translate
return translated_keys[k];
}
// Casio prototype
void GetKey(int * key){
*key=getkey(true);
}
void numworks_wait_1ms(int ms){
for (int i=0;i<ms/128;++i){
#ifdef SIMULATOR
Fl::wait(0.00001);
#endif
Ion::Keyboard::State scan = Ion::Keyboard::scan();
// if (scan!=16) std::cerr << scan << '\n';
Ion::Keyboard::Key interruptKey = static_cast<Ion::Keyboard::Key>(Ion::Keyboard::Key::Back);
if (scan.keyDown(interruptKey))
return;
Ion::Timing::msleep(128);
}
Ion::Timing::msleep(ms % 128);
}
Pour les traces, j'ai ajoute dans modkandinsky.cpp
- Code: Select all
#define LCD_WIDTH_PX 320
#define LCD_HEIGHT_PX 222
void numworks_giac_set_pixel(int x, int y, int color) {
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
if (ptr) ptr->displaySandbox();
KDColor c(color);
#if 1
if (x<0 || x>=LCD_WIDTH_PX || y<0 || y>=LCD_HEIGHT_PX)
return;
KDPoint point(x,y+18);
KDIonContext::sharedContext()->pushRect(KDRect(point, 1, 1), &c);
#else
KDPoint point(x,y);
KDIonContext::sharedContext()->setPixel(point,c);
#endif
}
void numworks_giac_fill_rect(int x,int y,int w,int h,int c){
KDColor color = c;
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
if (ptr) ptr->displaySandbox();
#if 1
if (x<0){
w += x;
x=0;
}
if (y<0){
h += y;
y=0;
}
if (h+y>=LCD_HEIGHT_PX)
h=LCD_HEIGHT_PX-y;
if (x+w>=LCD_WIDTH_PX)
w=LCD_WIDTH_PX-x;
if (h<=0 || w<=0)
return;
KDRect rect(x,y+18,w,h);
KDIonContext::sharedContext()->pushRectUniform(rect,color);
#else
KDRect rect(x,y,w,h);
KDIonContext::sharedContext()->fillRect(rect, color);
#endif
}
int numworks_giac_get_pixel(int x, int y) {
KDPoint point(x,y);
KDColor c = KDIonContext::sharedContext()->getPixel(point);
return c;
}
// renvoie la position horizontale en fin de trace
// si fake est true on n'ecrit rien, on calcule juste la longueur de l'affichage
int numworks_giac_draw_string(int x,int y,int c,int bg,const char * text,bool fake){
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
KDPoint point(x,y);
if (ptr)
ptr->displaySandbox();
auto ctx=KDIonContext::sharedContext();
KDRect save=ctx->m_clippingRect;
KDPoint o=ctx->m_origin;
ctx->setClippingRect(KDRect(0,18,320,fake?0:222));
ctx->setOrigin(KDPoint(0,18));
point=KDIonContext::sharedContext()->drawString(text, point, KDFont::LargeFont, c, bg);
ctx->setClippingRect(save);
ctx->setOrigin(o);
return point.x();
}
int numworks_giac_draw_string_small(int x,int y,int c,int bg,const char * text,bool fake){
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
KDPoint point(x,y);
if (ptr)
ptr->displaySandbox();
auto ctx=KDIonContext::sharedContext();
KDRect save=ctx->m_clippingRect;
KDPoint o=ctx->m_origin;
ctx->setClippingRect(KDRect(0,18,320,fake?0:222));
ctx->setOrigin(KDPoint(0,18));
point=ctx->drawString(text, point, KDFont::SmallFont, c, bg);
ctx->setClippingRect(save);
ctx->setOrigin(o);
return point.x();
}
void numworks_giac_hide_graph(){
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
if (ptr)
ptr->hideSandbox();
}
void numworks_giac_show_graph(){
auto ptr=MicroPython::ExecutionEnvironment::currentExecutionEnvironment();
if (ptr)
ptr->displaySandbox();
}
Le fichier kdisplay.h de giac-1.5.0 contient les declarations correspondantes, celle des touches (tres inspire du clavier Casio), ainsi que des fonctions d'UI, en particulier des menus a choix et un widget editeur de programmes, tout ca etant accessible sur le firmware delta+giac-1.5.0.