Solved Crash when calling TreeViewFunctions::DrawCell

I'm going to set a tree view as shown below. After adding items into the tree view for several times, it suddenly crashed in DrawText. This issue happens stably.
f0cdc856-582a-4526-b216-0ae3845dc2f9-image.png

42bad5c9-0d59-4ab2-b051-43baf46948f5-image.png

struct MyItem
{
	enum
	{
		MATERIAL,
		MESH,
		CAMERA,
		LIGTH
	};

	enum
	{
		OK,
		WARNING,
		ERROR
	};

	Int32 state = OK;
	Int32 type = MATERIAL;
	BaseList2D* element;
	String parameter;
	String problem;
};

struct MyItem
{
	Int32 state = OK;
	Int32 type = MATERIAL;
	BaseList2D* element;
	String parameter;
	String problem;
};

struct MyItemNode
{
	MyItem item; //data
	MyItemNode* down = nullptr;
	MyItemNode* next = nullptr;
};

using MyItemArray = maxon::BaseArray<MyItemNode>;

class MyTreeViewFunctions final : public TreeViewFunctions
{
	void* m_selected_node = nullptr;
public:
	static MyTreeViewFunctions& GetFunction()
	{
		static MyTreeViewFunctions func;
		return func;
	}

	void* GetFirst(void* root, void* userdata) override
	{
		return static_cast<MyItemArray*>(root)->GetFirst();
	}

	void* GetDown(void* root, void* userdata, void* obj) override
	{
		return nullptr;
	}

	void* GetNext(void* root, void* userdata, void* obj) override
	{
		if (const auto node = static_cast<MyItemNode*>(obj))
			return node->next;
		return nullptr;
	}

	Bool IsSelected(void* root, void* userdata, void* obj) override
	{
		return m_selected_node == obj;
	}

	Int32 GetLineHeight(void* root, void* userdata, void* obj, Int32 col, GeUserArea* area) override
	{
		return 20;
	}

	Int32 GetColumnWidth(void* root, void* userdata, void* obj, Int32 col, GeUserArea* area) override
	{
		return 65;
	}

	void DrawCell(void* root, void* userdata, void* obj, const Int32 col, DrawInfo* drawinfo, const GeData& bgColor) override
	{
		if(!obj)
			return;
		const auto& item = static_cast<MyItemNode*>(obj)->item;
		switch (col)
		{
		case MyDialog::LIST_COL_TYPE:
		{
			BaseBitmap* bm = nullptr;
			switch (item.type)
			{
			case MyItem::MATERIAL:
				bm = m_material_bitmap;
				break;
			case MyItem::MESH:
				bm = m_mesh_bitmap;
				break;
			case MyItem::CAMERA:
				bm = m_camera_bitmap;
				break;
			case MyItem::LIGTH:
				bm = m_light_bitmap;
				break;
			default:;
			}
			drawinfo->frame->DrawBitmap(bm, drawinfo->xpos + drawinfo->width / 4, drawinfo->ypos + 2, ICON_SIZE, ICON_SIZE, 0, 0, bm->GetBw(), bm->GetBh(), BMP_NORMALSCALED);
			break;
		}
		case MyDialog::LIST_COL_ELEMENT:
		{
			if (item.type == MyItem::MATERIAL)
			{
				if (auto* mat = reinterpret_cast<BaseMaterial*>(item.element); mat) 
				{
					if (BaseBitmap* bm = mat->GetPreview(0); bm)
					{
						drawinfo->frame->DrawBitmap(bm, drawinfo->xpos, drawinfo->ypos + 2, ICON_SIZE, ICON_SIZE, 0, 0, bm->GetBw(), bm->GetBh(), BMP_NORMALSCALED);
					}
				}
			}
			drawinfo->frame->DrawSetTextCol(IsSelected(root, userdata, obj) ? COLOR_TEXT_SELECTED : COLOR_TEXT, COLOR_TRANS);
			drawinfo->frame->DrawText(item.GetName(), drawinfo->xpos + ICON_SIZE + 2,drawinfo->ypos + drawinfo->height / 2, DRAWTEXT_VALIGN_CENTER);
			break;
		}
		case MyDialog::LIST_COL_PARAMETER:
		{
			drawinfo->frame->DrawSetTextCol(IsSelected(root, userdata, obj) ? COLOR_TEXT_SELECTED : COLOR_TEXT, COLOR_TRANS);
			drawinfo->frame->DrawText(item.parameter, drawinfo->xpos + 2,
				drawinfo->ypos + (drawinfo->height - drawinfo->frame->DrawGetFontHeight()) / 2 + 2);
			break;
		}
		case MyDialog::LIST_COL_PROBLEM:
		{
			drawinfo->frame->DrawSetTextCol(IsSelected(root, userdata, obj) ? COLOR_TEXT_SELECTED : COLOR_TEXT, COLOR_TRANS);
			drawinfo->frame->DrawText(item.problem, drawinfo->xpos + 2, drawinfo->ypos + drawinfo->height / 2, DRAWTEXT_VALIGN_CENTER);
			break;
		}
		default:;
		}
	}

	Bool IsOpened(void* root, void* userdata, void* obj) override
	{
		return true;
	}

	String GetName(void* root, void* userdata, void* obj) override
	{
		return {};
	}

	Int	GetId(void* root, void* userdata, void* obj) override
	{
		return 0;
	}

	Int32 GetDragType(void* root, void* userdata, void* obj) override
	{
		return NOTOK;
	}

	void Select(void* root, void* userdata, void* obj, Int32 mode) override
	{
		if(mode == SELECTION_SUB)
			m_selected_node = nullptr;
		else
			m_selected_node = obj;
	}
};

Hi @m_adam , thanks for your apply. I have solved this problem. The reason is I used maxon::BaseArray to store tree node data. When I append the array, the address of node may change, but the next pointer in node remain unchanged. And this cause the crash.

Hi @AiMiDi we are currently busy with other thing I will get to your topic as soon as possible, in the meantime I would say it is most likely the access of item.GetName() that went wrong since your item does not have a GetName method. (It is just a gut feeling I did not try your code).

Cheers,
Maxime.

Hi @AiMiDi if you need more help, please provide us a code that can compile so this means something that include the dialog as well, since this have an impact on how the treeview behave. On the same topic you do not provide the icon/ neither show how the m_xxx_bitmap are initialized.

Cheers,
Maxime.

Hi @m_adam , thanks for your apply. I have solved this problem. The reason is I used maxon::BaseArray to store tree node data. When I append the array, the address of node may change, but the next pointer in node remain unchanged. And this cause the crash.