Proper identification of exact State of an object

Description

I want to be able to know the state an object in text. I did not check if there is any function that returns the state as text and not only by the default value so i have created a simple function with a switch to do it.

By watching the struct there is question about the ORed states. What is the translation of status of 0x0010 . Is it only HOVERED or EDITED + FOCUSED

What MCU/Processor/Board and compiler are you using?

esp32,simulator

What LVGL version are you using?

8.3

What do you want to achieve?

To be able to identify the text. Some of the values of the enum if agregated the fall into other values that are not for the same reason

What have you tried so far?

Tried to create a function that calls the get state function for an event and return proper text that describes the current state by trying to answer also for the ORed states.
When i select a text area i get a state with value 34 which could be either:

  1. LV_STATE_PRESSED | LV_STATE_HOVERED | LV_STATE_FOCUS_KEY
  2. LV_STATE_PRESSED | LV_STATE_EDITED | LV_STATE_FOCUS_KEY | LV_STATE_FOCUSED
    I assume it is the first but ok it is still not clear.
    Is there a proper way to identify that i have missed ? Something already existing?

Code to reproduce

// this is the  default states from lvgl
enum {
    LV_STATE_DEFAULT     =  0x0000,
    LV_STATE_CHECKED     =  0x0001,
    LV_STATE_FOCUSED     =  0x0002,
    LV_STATE_FOCUS_KEY   =  0x0004,
    LV_STATE_EDITED      =  0x0008,
    LV_STATE_HOVERED     =  0x0010,
    LV_STATE_PRESSED     =  0x0020,
    LV_STATE_SCROLLED    =  0x0040,
    LV_STATE_DISABLED    =  0x0080,

    LV_STATE_USER_1      =  0x1000,
    LV_STATE_USER_2      =  0x2000,
    LV_STATE_USER_3      =  0x4000,
    LV_STATE_USER_4      =  0x8000,

    LV_STATE_ANY = 0xFFFF,    /**< Special value can be used in some functions to target all states*/
};

typedef uint16_t lv_state_t;

//and what i did
char* str_get_obj_state(lv_obj_t* obj){

	lv_state_t state=lv_obj_get_state(obj);

	switch(state){
	case 0x0000:
		return "LV_STATE_DEFAULT";
		break;
	case 0x0001:
		return "LV_STATE_CHECKED";
		break;
	case 0x0002:
		return "LV_STATE_FOCUSED";
		break;
	case 0x0003:
		return "LV_STATE_CHECKED & LV_STATE_FOCUSED";
		break;
	case 0x0004:
		return "LV_STATE_FOCUS_KEY";
		break;
	case 0x0005:
		return "LV_STATE_CHECKED & LV_STATE_FOCUS_KEY";
		break;
	case 0x0006:
		return "LV_STATE_FOCUSED & LV_STATE_FOCUS_KEY";
		break;
	case 0x0007:
		return "LV_STATE_CHECKED & LV_STATE_FOCUSED & LV_STATE_FOCUS_KEY";
		break;
	case 0x0008:
		return "LV_STATE_EDITED";
		break;
	case 0x0009:
		return "LV_STATE_CHECKED & LV_STATE_EDITED";
		break;
	case 0x0010:
		return "LV_STATE_HOVERED"; // this could also be EDITED+FOCUSED
		break;
	default:
		LV_LOG_USER("unIdentified state: %d",state);
		return "Will check the rest";
		break;
	}
	return "";
}

Hi @kyrpav ,

I think unfortunately you can’t really use a switch/case type approach to this problem. As you have discovered when we are using bitwise flags the ‘switch value’ can be duplicated for different combinations of state.
I would suggest a different approach, where you check each bit individually and build an appropriate text, see below:

#define MAX_SIMULTANEOUS_STATES	 (sizeof(lv_state_t) * 8)
char *txt_states[] = {

	"LV_STATE_DEFAULT",
	"LV_STATE_CHECKED",
	"LV_STATE_FOCUSED",
	"LV_STATE_FOCUS_KEY",
	"LV_STATE_EDITED",
	"LV_STATE_HOVERED",
	"LV_STATE_PRESSED",
	"LV_STATE_SCROLLED",
	"LV_STATE_DISABLED",
	"LV_STATE_UNDEFINED_1",
	"LV_STATE_UNDEFINED_2",
	"LV_STATE_UNDEFINED_3",
	"LV_STATE_UNDEFINED_4",
	"LV_STATE_USER_1",
	"LV_STATE_USER_2",
	"LV_STATE_USER_3",
	"LV_STATE_USER_4"
};


uint8_t str_get_obj_state(lv_obj_t *obj, char *set_states[] ) {

	uint8_t		no_of_states = 0, cnt = 1;
	lv_state_t	state=lv_obj_get_state(obj), mask;

	if( !state ) {
		set_states[0] = txt_states[0];
		no_of_states++;
	} else {
		for( mask = 0x0001; mask != 0; mask <<= 1, cnt++ ) {
			if( state & mask ) {
				set_states[no_of_states++] = txt_states[cnt];
			}
		}
	}
	return no_of_states;
}



int main(int argc, char **argv) {
	
	char *set_states[MAX_SIMULTANEOUS_STATES];
	uint8_t	states;

	states = str_get_obj_state(lv_scr_act(), set_states );

	if( states == 1 ) {
		printf( "%s\n", set_states[0] );
	} else if( states > 1 ) {
		for( uint8_t i = 0; i < states; i++ ) {
			if( states - i == 1 ) printf( "%s\n", set_states[i] );
			else printf( "%s & ", set_states[i] );
		}
	}
}

This is just a quick and dirty untested approach but hopefully will give you a template to work with.

Hope this helps.

Kind Regards,

Pete

Looks like both of you have been deceived by your base 10 brains.

Bit flags and combinations of flags are unique - that’s why we use them.
@kyrpav your implementation is correct but you have been thrown by decimal arithmetic 8 + 2 = 10 == 0x0A
After case 0x0009: you should have implemented case 0x000A: not 0x0010
LV_STATE_CHECKED | LV_STATE_EDITED == 0xA

LV_STATE_HOVERED = 0x0010, which is 16 decimal.

For your example (assuming decimal) state 34 =
LV_STATE_DEFAULT | LV_STATE_CHECKED | LV_STATE_FOCUS_KEY | LV_STATE_HOVERED

axaxaxaxa thank you i completely forgot 0x, and also lost
typedef uint16_t lv_state_t;

Though since if %d switch prints 34 this mean that in hex should be 0x22 couldn’t this be just LV_STATE_PRESSED | LV_STATE_FOCUSED directly? Which is more logical to happen when someone selected a textarea?

Correct. I have numerical dyslexia and typed 43 into my calculator.

Based on all previous i fixed one function to get the states in pattern of “state & state & state”

In order not to confuse i have created a string array with alla values from 0x01 to 0x0F and then 0x10 to 0xF0, so program iterates twice to get these states in the same way

char* str_get_obj_state2(lv_obj_t* obj){

	lv_state_t state=lv_obj_get_state(obj);
	char stateList[32][150]={"LV_STATE_DEFAULT","LV_STATE_CHECKED","LV_STATE_FOCUSED","LV_STATE_FOCUSED & LV_STATE_CHECKED",
			"LV_STATE_FOCUS_KEY","LV_STATE_FOCUS_KEY & LV_STATE_CHECKED","LV_STATE_FOCUS_KEY & LV_STATE_FOCUSED",
			"LV_STATE_FOCUS_KEY & LV_STATE_CHECKED & LV_STATE_FOCUSED","LV_STATE_EDITED","LV_STATE_EDITED & LV_STATE_CHECKED",
			"LV_STATE_EDITED & LV_STATE_FOCUSED","LV_STATE_EDITED & LV_STATE_FOCUSED & LV_STATE_CHECKED",
			"LV_STATE_EDITED & LV_STATE_FOCUS_KEY","LV_STATE_EDITED & LV_STATE_FOCUS_KEY & LV_STATE_CHECKED",
			"LV_STATE_EDITED & LV_STATE_FOCUS_KEY & LV_STATE_FOCUSED","LV_STATE_EDITED & LV_STATE_FOCUS_KEY & LV_STATE_CHECKED & LV_STATE_FOCUSED",
			"LV_STATE_HOVERED","LV_STATE_PRESSED","LV_STATE_PRESSED & LV_STATE_HOVERED","LV_STATE_SCROLLED",
			"LV_STATE_SCROLLED & LV_STATE_HOVERED","LV_STATE_SCROLLED & LV_STATE_PRESSED","LV_STATE_SCROLLED & LV_STATE_PRESSED & LV_STATE_HOVERED",
			"LV_STATE_DISABLED","LV_STATE_DISABLED & LV_STATE_HOVERED","LV_STATE_DISABLED & LV_STATE_PRESSED",
			"LV_STATE_DISABLED & LV_STATE_PRESSED & LV_STATE_HOVERED","LV_STATE_DISABLED & LV_STATE_SCROLLED",
			"LV_STATE_DISABLED & LV_STATE_SCROLLED & LV_STATE_HOVERED","LV_STATE_DISABLED & LV_STATE_SCROLLED & LV_STATE_PRESSED",
			"LV_STATE_DISABLED & LV_STATE_SCROLLED & LV_STATE_PRESSED & LV_STATE_HOVERED"
	};

	char *result=(char*)malloc(200 * sizeof(char));
	uint8_t index=0;
	bool initial=true;
	for( lv_state_t mask = 0x0000; mask <= 0x000F; mask +=0x0001 ,index++) {
		if( ((state & 0x000F) ^ mask)==0 ) {
			if(initial){
				strcpy(result,stateList[index]);
				initial=false;
				continue;
			}else{
				strcat(result," & ");
			}
			strcat(result,stateList[index]);
		}

		if((state & 0x000F) < mask)
			break;
	}
	
	index=16;
	for( lv_state_t mask = 0x0010; mask <= 0x00F0; mask +=0x0010 ,index++) {
		if( ((state & 0x00F0) ^ mask )==0) {
			strcat(result," & ");
			strcat(result,stateList[index]);
		}
		if((state & 0x00F0) < mask)
			break;
	}

	return result;
}

I assume that after disabled state the rest could have been omitted but i left them there.