Message |
|
Could you send me emf file for that. Feel free to PM it to me if you wish. I’ll take a look at it on our Linux box.
|
 |
|
Something similar to that will be in version 2.0 of the library once released. You can register a handler for when the main title is clicked or touched. It is supported on all graphical renderers. You can see it used in a few of the new examples.
However 2.0 library is still a little way off while we fully test it.
|
 |
|
Again really good to see tcMenu in use, I like the magnifying glass on the display!
|
 |
|
This is great, it's always good to see where tcMenu is used!
On the display, in rugged equipment I think LCD is about the best option, I've broken a couple of OLEDs on the bench as they are so fragile.
|
 |
|
I think that I would do this for now with a scroll choice item. You can move them up and down in value and although it seems odd to use what's essentially a choice element for this, you could for example provide 255 choices using the custom render function option, with your own text and value for each one. Take a look at the scroll choice guide and see what you think. That would work right now, with tcMenu 1.7 out of the box.
https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menu-item-types/scrollchoice-menu-item/
EDIT: just to reiterate I'm not talking about using the memory or eeprom array option, I'm talking about using the custom function option, where you'd be called back whenever a values was needed, or when it was selected. The above guide goes through this option in the section "Custom rendering option".
|
 |
|
Yes, the ESPAmplifer or many of the other examples have a scale in dB. The dB scale is essentially presented completely as linear, but the calculations are done by a volume control IC, such as a PGA2310 which accurately increases volume in steps of 0.5dB. So the non-linearity of the scale is handled there (I suspect using a table in the IC).
If you needed to do the calculation yourself, would you not just do the math (or provide a table of values) to convert the display units into actual units.
Maybe I am oversimplifying here. But let us say you had 255 steps in your menu item, something like this may be the simplest approach:
const uint32_t valueToActualMap[256] = {.......}; // populated with your values, ensure it's stored in flash by using PROGMEM if needed
void onMenuItemChanged(int /*id*/) {
int val = menuItem.getCurrentValue(); // returns between 0 and 255
uint32_t corrected = volumeToActualMap[val];
// do something here with corrected
}
The other option would be to use an editable large number, which can handle values of huge range, up to 12 significant figures, with up to 9 of those being the whole part. You can read about those here: https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menu-item-types/largenum-menu-item/
|
 |
|
We’ve mainly done this with dB for audio purposes so that the display scale looks linear. But beyond that I don’t think we’ve really considered anything else. Would something like that not work here? The other option would be to use a large number.
|
 |
|
Hi there good to know that Linux is being tested. We’ll be making a proper release of it soon.
The file extension for a designer project should be .emf
|
 |
|
Yep it was held, just a typo on my part copying and pasting.
|
 |
|
The issue is: Using the Encoder to operate the menu does not work: The display shows no move of the cursor to submenus or similar, a test using the Encoder Button for a callback also failed.
Ah, I think I see how you're using it now. I assume you've told the designer UI not to automatically create any rotary encoder or input device on your behalf, and instead you've created them manually yourself in the main setup method.
edit - If this is the case just make sure that you have "no input" selected in the designer.
If that is the case, you just need to ensure that when the rotary encoder changes that you tell menuMgr about it, by calling the following from your encoder change callback when the menu is active:
void onEncoderChange(int newValue)
{
menuMgr.valueChanged(newValue); // as you are managing things manually, you need to let menu manager know when this changes, unless you've taken over display
}
I see you're also managing the button yourself too, same applies here. When the menu is active and the button is released, call:
void onReleased(uint8_t pin, bool held) override {
Serial.println("Released ");
menuMgr.onMenuSelect(wasHeld); // as you are managing things manually, you need to let menu manager know when this changes, unless you've taken over display
}
This will allow you to keep control of the rotary encoder and select button, but at the same time allow the menu manager to handle the events when it's active.
|
 |
|
Also, one last thing, you shouldn't need to set the pin modes on the encoder and switches yourself, the library will do it for you. Also you can't take a listener on the switch that is on the encoder, it's used by tcMenu internally, and a switch can only have one listener.
There are two ways you can get around this.
1/ in the takeOverDisplay rendering callback, the two parameters are the position of the encoder, and the button press state is one of the following values:
RPRESS_NONE = 0,
RPRESS_PRESSED = 1,
RPRESS_HELD = 2
2/ You could handle the button yourself, in that case I'd recommend setting up the encoder and switch in your own code and following the section on setting up the menu control manually in this guide: https://www.thecoderscorner.com/products/arduino-libraries/tc-menu/menumanager-and-iteration/
|
 |
|
Also in terms of having to take over the display just to get better fonts and drawing. That shouldn't be needed from 2.0 onwards, the UI is completely skinnable, and can even be re-skinned while it's running, or custom per submenu or item.
|
 |
|
I think I can see what's wrong, you are setting up the multiIO AFTER setupMenu(). However the switches and rotary encoder initialisation happens in setupMenu. Try moving it just after Wire.begin(). In fact for safety setupMenu should be after Wire.begin too.
TcMenu i can only operate if i do not use setupRotaryEncoderWithInterrupt(encoderAPin, encoderBPin, onEncoderChange, HWACCEL_REGULAR);
Using that setup of the Encoder does have as consequence the Encoder does not react in TcMenu.
I suspect this is the above. However, I'm not really sure what you mean by you can't use that function? Can you not use the function because it doesn't work, or for some other reason?
IoAbstractionRef multiIoENC = ioFrom8754(0x20, 2); i need for TcMenu, without there's no reaction in the Menu, with it does run like a charm.
Being confused a bit as i cannot get an idea how the pins are defined then.
The code you provided in the orginal post looks right to me in terms of setup but just in the wrong place. Try moving before setupMenu.
How to setup the Encoder in an multiIoAbstraction for TcMenu
As above.
and another Renderer as e.g. using an standard 1366 library ( E.g. Adafruit ) ?
You can use any library that's compatible with Adafruit_GFX or you can use U8G2. When 2.0 comes out, we'll also support TFT_eSPI and LTDC frame buffer. You'd just use the custom Adafruit_GFX renderer option. In that case you create the variable yourself and just tell tcMenu the variable name you've created, and the class / include header name.
|
 |
|
You can schedule and cancel in any order, but you're better not relying on cancel for regular operation. It's a very heavy operation that has itself to wait for scheduling. There is no guarantee that it will happen before the next execution.
Cancelling a task involves scheduling a task for immediate execution that will go through the running queue and remove the task that is to be scheduled.
It's better when the event timing changes often to use the schedule once as shown in my example. You could also use a polling event as described in the task manager docs.
|
 |
|
What I would do in your case is use scheduleOnce as follows, then it will always use the correct time:
void myTimerTask() {
// other work to be done
taskManager.scheduleOnce(menuTime.getCurrentValue(), myTimerTask, TIME_SECONDS);
}
myInitialisation() {
taskManager.scheduleOnce(menuTime.getCurrentValue(), myTimerTask, TIME_SECONDS);
}
|
 |
|