neu-rah / ArduinoMenu

Arduino generic menu/interactivity system
GNU Lesser General Public License v2.1
951 stars 191 forks source link

Adding an event? #262

Closed MagicDanielle closed 4 years ago

MagicDanielle commented 4 years ago

Hello. I am currently using a modified version of this menu on a TTGO T-display:

https://i.ibb.co/9wMbFNj/20191111-183900.jpg https://i.ibb.co/4pRmMkn/20191111-190714.jpg

When I click "start dice" I need to display a screen that shows a dice face which changes depending on the orientation of the dice. For now I will be happy with "start dice" just displaying an image of a dice that will change when needed. Once I know how to do this, I think I will be able to edit it to do more things.

Now I think I need to start my dice screen as an event, but it just drops an image over the top of the menu. Should I be idling the menu? I need the dice image to change to a different number when needed. The wiki page is so confusing I just cant get to grips with it.

I currently have this. Am I even close?

result dice_1(menuOut& o,idleEvent e) {
  if (e==idling) {
      gfx.fillScreen(TFT_BLACK);
  gfx.fillRoundRect(70, 20, 100, 100, 8, TFT_WHITE);
  gfx.fillCircle(120, 70, 8, TFT_BLACK);
  return proceed;
  }
  return proceed;
}
//and this is the menu calling it.
MENU(dice,"Dice Orientation",doNothing,noEvent,noStyle
,OP("Start Dice",dice_1,enterEvent) //<<<<<<< **right here**
,SUBMENU(diceOpt)
,EXIT("<Back")
);

After tinkering with the code, I can get the dice image to display over the top of the menu, but this is literally just drawing it over the top, and the menu is still active behind.

Thank you in advance for any help you can give me.

MagicDanielle commented 4 years ago

Helloooo?

neu-rah commented 4 years ago

Hi! sorry for the delay

menu handlers can use the display if you don't mind that menu and main loop being interrupted as long as you do your stuff inside the handler. For some its not acceptable... maybe because there is other stuff on the main loop.

menu can be put on idle or non executing mode, if not calling the menu poll function (or doInput/doOutput) the menu wont even notice and a signal must be sent to menu on resume so that it redraws the screen

there is also a menu idling system, enter by calling navigation system idleOn function with a idle handler.

details are here https://github.com/neu-rah/ArduinoMenu/wiki/Idling

feel free to join us on gitter https://gitter.im/ArduinoMenu/Lobby

MagicDanielle commented 4 years ago

Actually the thing is, I've been looking at that wiki for hours and trying everything. I simply can't get the menu to idle. I don't know how to write the specific lines of code to make it do it. The only thing I can succesfully do is draw my dice over the top of it. Can you advise me on specific format of code in my use case? I really wish I had examples of a program displaying screens outside the menu, with the menu idling so I could reverse engineer it for my purpose.

neu-rah commented 4 years ago

and what would start such an event? would it be started by a menu option or by some external condition/logic?

MagicDanielle commented 4 years ago

I need the event to be started by a menu option. The event needs to be dynamic though, so once started, it is always waiting for new data. The images i posted in my op display what I need to happen...

"Start dice is selected in menu" A screen displays an image of a dice The dice value changes depending on information received. Exit back to sub-menu when finished.

neu-rah commented 4 years ago

an example of handler https://github.com/neu-rah/ArduinoMenu/blob/master/examples/Serial/serialio/serialio/serialio.ino#L28

this function will be called with eventMask code (can also be void)

associating the hjandler with a menu prompt: https://github.com/neu-rah/ArduinoMenu/blob/master/examples/Serial/serialio/serialio/serialio.ino#L113 (same handler can be shared)

all elements allow an handler and an event mask (determines what events will be sent)

event codes are here https://github.com/neu-rah/ArduinoMenu/blob/master/src/menuBase.h#L115

MagicDanielle commented 4 years ago

Oh wow, thank you so much. I will have a tinker with this later :)

MagicDanielle commented 4 years ago

When I start the event, the dice comes up on screen. Button 1 does nothing, but button 2 is still navigating the menu behind the dice image. When I press button 2 the menu just jumps in front of the dice like this...

20191115_152730

I need to be able to have button functionality in that event, but it seems to still just be acting as a cover over the menu. This still doesn't seem right.

I'm using these:

result dice1(eventMask e) {
  gfx.fillScreen(TFT_BLACK);
  gfx.fillRoundRect(70, 20, 100, 100, 8, TFT_WHITE);
  gfx.fillCircle(120, 70, 8, TFT_BLACK);
  return proceed;
}
MENU(dice,"Dice Orientation",doNothing,noEvent,noStyle
  ,OP("Start Dice",dice1,anyEvent)
  ,SUBMENU(diceOpt)
  ,EXIT("<Back")
);
enum eventMask {
      noEvent=0,//just ignore all stuff
      activateEvent=1,//this item is about to be active (system event)
      enterEvent=1<<1,//entering navigation level (this menu is now active)
      exitEvent=1<<2,//leaving navigation level
      returnEvent=1<<3,//TODO:entering previous level (return)
      focusEvent=1<<4,//element just gained focus
      blurEvent=1<<5,//element about to lose focus
      selFocusEvent=1<<6,//TODO:child just gained focus
      selBlurEvent=1<<7,//TODO:child about to lose focus
      updateEvent=1<<8,//Field value has been updated
      anyEvent=~0
    };

I need the buttons to stop interacting with the menu, unless I press the back button.

neu-rah commented 4 years ago

its because you are returning from your event, to use events like that you should do a loop inside your event and only return to resume the menu

i'm assuming that once on the event you wont need the menu

MagicDanielle commented 4 years ago

yes, while the event is active, I wont need the menu anymore. any examples of loops inside event?

neu-rah commented 4 years ago

nope, but its normal c++, you can do whatever needed inside the handler

didnt compile this, but should be something similar


result dice1(eventMask e) {
  do {
    gfx.fillScreen(TFT_BLACK);
    gfx.fillRoundRect(70, 20, 100, 100, 8, TFT_WHITE);
    //get random dice state here
    //draw the state:
    gfx.fillCircle(120, 70, 8, TFT_BLACK);
    while(!digitalRead(SOME_AGAIN_BTN));
  } while(digitalRead(SOME_EXIT_BTN_PIN));
  return proceed;
}
MagicDanielle commented 4 years ago

perfect :) Thank you