Changing font size in text element of cell [CONNECT MDL C++]

Hello guys! I have a question.

I want to do following: 

  1. Retrieve element descriptor of a given cell and duplicate it.
  2. This cell contains text elements, I want to modify their font size. 
  3. During whole process, display said element descriptor in temporary mode.

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?

Parents
  • Hi Lubo,

    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:

    • Write code to modify any simple element (e.g. line) inside cell.
    • Write code to modify text (simple text or text node).
    • Merge this two codes together.

    And, as Jon wrote, never use element descriptor :-)

    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

  • Stop!  Forget element descriptors — they are so 20th century.  Work with ElementHandles and EditElementHandles when writing C++ for CONNECT
    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.

    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

  • 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
    }

     
    Regards, Jon Summers
    LA Solutions

  • Hi Lubo,

    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.

    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.

    But what about modifying element?

    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.

    Regards,

      Jan

  • 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

  • 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.

    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?

    Regards,

      Jan

  • Do you mean dynamics (frame update) when element tool is implemented?

    Yes, it is during the dynamics. 

    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.

  • 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.

    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.

    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

  • 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.

    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

  • Well I found a working solution. I couldn´t get the new API to work the way as I wanted (or I didn´t find a proper way yet), but I managed it to work with old mdlText_create function. The thing is, in V8I, I was using mdlText_createWide, and after you used this function for text element, it recreated the text element with same font, style etc (even though I passed nullptr as arguments for these) . But in CONNECT, it recreates text element + it also "resets" other stuff. So I had to pass these parameters to this function as well (even though they were unchanged). This way, I got the element I wanted with changed font size.

Reply
  • Well I found a working solution. I couldn´t get the new API to work the way as I wanted (or I didn´t find a proper way yet), but I managed it to work with old mdlText_create function. The thing is, in V8I, I was using mdlText_createWide, and after you used this function for text element, it recreated the text element with same font, style etc (even though I passed nullptr as arguments for these) . But in CONNECT, it recreates text element + it also "resets" other stuff. So I had to pass these parameters to this function as well (even though they were unchanged). This way, I got the element I wanted with changed font size.

Children
  • Hi Lubo,

    but I managed it to work with old mdlText_create function.

    your question was how to change the font size for (existing) text, so I am not sure how "text create" function can be the solution?

    But in CONNECT, it recreates text element + it also "resets" other stuff.

    I have no experience with native API in CE in this case, but TextBlock API, available in NET (which is a think wrapper around the same native API), does allow really to modify (replace) text or to change parameters, whereas other settings are maintained.  I did not do any detail testing whether all data (user attributes, XAttributes/EC data) is maintained, but I guess they are, because the element is not created as a new one from scratch.

    This way, I got the element I wanted with changed font size.

    As I wrote earlier, to change the font size can be achieved several different ways. Without a help of text style (which is always preferred), the size can be set at "run level", and it works just fine.

    Regards,

      Jan