Hello guys! I have a question.
I want to do following:
Before I was working with V8I implementation, here everything worked fine :
I iterate through said cell descriptor. Whenever I found element with type TEXT_ELM, I changed its font size.
For extraction I used:
mdlText_extract(to extract TextSize from element). Change parameters in extracted TextSize structure. Recreate element with new font size, using mdlText_createW(myElement,myElement,NULL,NULL,NULL,&extractedSize,NULL,NULL,modelRef)
And all worked fine. However, in CONNECT it doesn´t work as expected. I managed it to work, so it changes the font size, but styling and transform suddenly disappears, so I´ve decided to check the new way with EditElementHandle and TextBlock API.
What I tried to do was (simple test to replace existing text) :
ElementHandle eh(out,modelRefP); //out is my MSElement extracted from MSElementDescr iteration i talked before EditElementHandle eeh(out, modelRefP); // Check if the selection is a Text element. ITextQueryCP textQuery = eh.GetITextQuery(); if (!textQuery || !textQuery->IsTextElement(eh)) return 1; // Extract the TextBlock from the Text element. ITextPartIdPtr textPart; TextBlockPtr textBlock = textQuery->GetTextPart(eh, *textPart); if (textBlock.IsNull() || textBlock->IsEmpty()) return 1; // Get the string from the Text block. WString str = textBlock->ToString(); if (str.empty()) return 1; RunPropertiesPtr runPropP = textBlock->GetRunPropertiesForAdd().Clone(); DPoint2d fontSize = runPropP->GetFontSize(); fontSize.x = 20; fontSize.y = 20; runPropP->SetFontSize(fontSize); textBlock->SetRunPropertiesForAdd(*runPropP); CaretPtr searchStart = textBlock->CreateStartCaret(); CaretPtr end = textBlock->CreateEndCaret(); textBlock->Remove(*searchStart,*end); EditElementHandle eeh2; textBlock->AppendText(L"Test"); TextBlockToElementResult res2 = TextHandlerBase::CreateElement(eeh2, nullptr, *textBlock);
My idea was to remove and re-enter same text with different properties, because I couldn´t find a way to do it without that (maybe there is some? Remapping doesn´t involve font size) and changing the RunProperties affects only actions that happen after it is set...
And, as you maybe expected, nothing happens, the text is same. I know that you can call AddToModel (then it appears in model, but the original is still same). I also saw ReplaceInModel function, but the elements have no ElementRef yet.
I´ve tried this (with a little hope):
*out = *eeh2.getElementP();
But i got segfault during the iteration of next elements
Do you guys know how to approach something like this?
Lubo B said:Retrieve element descriptor
Stop! Forget element descriptors — they are so 20th century. Work with ElementHandles and EditElementHandles when writing C++ for CONNECT.
ElementHandle
EditElementHandle
Those are smart pointers that encapsulate an element descriptor and manage its lifetime, so you don't have to.
Lubo B said:I´ve tried this (with a little hope):*out = *eeh2.getElementP();
Use the ChildElemIter.
Regards, Jon Summers LA Solutions
Hi Lubo,
Lubo B said:Changing font size in text element of cell
in my opinion to modify text inside cell is one from the most demanding operation in CE API ;-)
... and e.g. in NET I was not able to find a way how to do it (there are several discussions in this forum about this topic), but I am not sure whether the problem is in native API or in the wrapper to CE.
I recommend to split the solution into several independent steps / tests and when everything is working, to merge the code together:
And, as Jon wrote, never use element descriptor :-)
Lubo B said:My idea was to remove and re-enter same text with different properties, because I couldn´t find a way to do it without that
It's not the right approach. Search for discussions targeting this topic (e.g. this recent one).
I assume there are more ways how to do it, depending whether your text is simple one or complex, but methods like GetRunPropertiesForAd and SetRunPropertiesForAd should help you.
Regards,
Jan
Bentley Accredited Developer: iTwin Platform - AssociateLabyrinth Technology | dev.notes() | cad.point
Jon Summers said:Stop! Forget element descriptors — they are so 20th century. Work with ElementHandles and EditElementHandles when writing C++ for CONNECT
Jan Šlegr said:And, as Jon wrote, never use element descriptor :-)
I know you guys would say that. As I´m working with older codebase, I´m using foundation where some methods work with descriptors. So i´m trying to make smallest changes as possible, to avoid influencing big part of the system.
Jan Šlegr said:I assume there are more ways how to do it, depending whether your text is simple one or complex, but methods like GetRunPropertiesForAd and SetRunPropertiesForAd should help you.
But what about modifying element? RunPropertiesForAdd take effect only if you for example add text to existing element, it doesn´t change the property of existing text. Or maybe I´m missing something
Lubo B said:But what about modifying element?
Many functions that create an element take a template as an argument. The template is an existing element. For example...
ElementHandle existingText = // get text element EditElementHandle replacementText; if (TEXTBLOCK_TO_ELEMENT_RESULT_Success == TextHandlerBase::CreateElement(replacementText, existingText, textBlock)) { // do something with replacementText // existingText provides an elementRef when replacing the text element }
Lubo B said:So i´m trying to make smallest changes as possible, to avoid influencing big part of the system.
In my opinion it's not the right approach, at least from a long-term perspective. But without knowing details and context, it's just subjective guess. Best practices how to refactor and update legacy code is well known and described (even though the most of developer probably have zero knowledge of them, because legacy code maintenance is a specialization in itself ;-)
I agree to change everything to new code and API is not possible and in fact does not make any sense (because descriptors are normally supported and works fine), so it's about wrapping new code into testable individual methods/classes that mimics old internal interface.
Lubo B said:RunPropertiesForAdd take effect only if you for example add text to existing element, it doesn´t change the property of existing text.
Oops. you are probably right.
In my opinion it depends a lot on how your texts are created. When text styles are used, it's only about to change the style, which can be done at TextBlock level. But when it's a plain text, you have to go "down to runs" and to change font size there. And, of course, to replace text block and also replace element in model.
Jan Šlegr said:and to change font size there. And, of course, to replace text block and also replace element in model.
Yes. I´ve noticed the ReplaceInModel method, but it is taking an ElementRef of original element as a parameter. However, the cell I´m modifying is displayed in TEMP_DRAW mode, so thus it has no ElementRef
Lubo B said:I´ve noticed the ReplaceInModel method, but it is taking an ElementRef of original element as a parameter. However, the cell I´m modifying
My answer was about changing font size in text element (text or text node), where the workflow ends with replacement of old element by new element.
Lubo B said:However, the cell I´m modifying is displayed in TEMP_DRAW mode, so thus it has no ElementRef
So far, you do not mention anything about displaying the element. Do not make the discussion chaotic and confusing adding extra conditions and requirements. Until you are able to (A) modify text parameters and (B) modify a cell content, why to discuss how to display it?
When there will be working code, ask in a new post, how to work with ElementRefs. But, you have to also provide explanation and probably also code why TEMP_DRAW is used ... I do not know anything about it? Do you mean dynamics (frame update) when element tool is implemented?
Jan Šlegr said:Do you mean dynamics (frame update) when element tool is implemented?
Yes, it is during the dynamics.
Jan Šlegr said:My answer was about changing font size in text element (text or text node), where the workflow ends with replacement of old element by new element.
Yes! But so far I havent found the solution for that. I found the approach i discussed (remove old text, change font text for upcoming changes and then place the same text with same settings), but it is odd. And doesn´t replace original content.
Lubo B said:But so far I havent found the solution for that.
You do not share any such information until now. To set what information was helpful and, when possible, to mark a relevant post as answer, is a part of good manner. And it also helps "future readers" to find answers, that are treated as the most valuable by others.
Lubo B said:I found the approach i discussed (remove old text, change font text for upcoming changes and then place the same text with same settings), but it is odd.
I do not know you code, but it sounds really weird. Nothing like to remove text is necessary: To replace text using TextBlock API and to change necessary setting does not require to remove anything upfront. And for sure (at least when talking about text outside cell), to replace, no new placement, is the right way.
Lubo B said:Yes, it is during the dynamics.
Again, as I wrote, ask in the new post and do not steal own discussion with a new topic.
To share / explain code is necessary, because I do not see any requirement for ElementRef when any from DgnTool(s) is implemented, because ElementAgenda (based on handlers) is used when OnDynamicFrame is called.
I am even not able to find anything like TEMP_DRAW in CE API headers. So is it real functional CE code?
With regards,
Jan Šlegr said:You do not share any such information until now. To set what information was helpful and, when possible, to mark a relevant post as answer, is a part of good manner. And it also helps "future readers" to find answers, that are treated as the most valuable by others.
Don´t worry. I always share the solution if I find it, fact that I haven´t shared anything was because I haven´t figured it out yet.
Jan Šlegr said:I am even not able to find anything like TEMP_DRAW in CE API headers. So is it real functional CE code?
I think that should really have its own thread. But, yea it is working, even though I´m using legacy approach with mdlElmdscr_display, the enum is not mentioned in documentation, but is in headers. The right name in CE is DRAW_MODE_TempDraw. I used the term TEMP_DRAW, because I remembered it has temp draw in name, but forgot the right prefixes, I apologise for confusion