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.