itwinjs-core icon indicating copy to clipboard operation
itwinjs-core copied to clipboard

TextBox

Open Josh-Schifter opened this issue 11 months ago • 18 comments

Together, these proposals are intended to support a ‘TextBox’ behavior similar to PowerPoint.

  1. Add margin to TextBlock.
  2. Add a Height property to either TextBlock or TextAnnotation
  3. Add text frame shape to TextAnnotation2d.
  4. We should remove either TextBlock.justification or TextAnnotation.Anchor.horizontal. They are redundant

Also, I think we need to seriously consider how we will implement leaders and how they attach to text. I have some ideas.

The Drawing Production team stands ready to help.

@pmconne, @claudiaareneee , @SheetalNair , @Alfonso-Martello

Related to Issue: Text Leader

Josh-Schifter avatar Feb 17 '25 21:02 Josh-Schifter

We should remove either TextBlock.justification or TextAnnotation.Anchor.horizontal. They are redundant

Please explain why you consider them redundant. Anchor point is orthogonal to text justification.

Add a Height property to either TextBlock or TextAnnotation

Is this to control the height of the text frame shape? If not, please explain your motivation.

Add margin to TextBlock.

Is this to control the width of the text frame shape? If not, please explain your motivation.

Also, I think we need to seriously consider how we will implement leaders and how they attach to text. I have some ideas.

Please elaborate. FWIW, @jffmarker had concepts of AnnotationFrameStyle and AnnotationLeaderStyle in the C++ implementation of text annotations which to my understanding were never used.

pmconne avatar Feb 17 '25 21:02 pmconne

@Josh-Schifter, I made these issues:

  1. #7675
  2. #7676
  3. #7677 (not an exact overlap, but could be reworked)

Could these help explain the motivations?

claudiaareneee avatar Feb 17 '25 21:02 claudiaareneee

Could these help explain the motivations?

Not really. They all specify what you want on a technical level, not why you (or users) want it, except for a mention of legibility on the fillColor one.

It seems like most of the issues you previously filed and now Josh has enumerated in this issue's description revolve around this concept of a "TextBox". I'm trying to understand what problem(s) you intend to solve by introducing a "TextBox behavior similar to PowerPoint". Your fillColor issue mentions possibly using an oval shape instead of a box - is that also a kind of "TextBox"?

I'm not trying to be difficult. I want to make sure we nail down what a TextBox is and what it's used for before we get into "TextBlocks should have X" level of detail?

pmconne avatar Feb 17 '25 23:02 pmconne

In C++ land, I was still trying to mimic primarily what MicroStation and AutoCAD had in terms of text. If you're going for a PowerPoint-type presentation, what I had is probably insufficient since that wasn't my intent.

jffmarker avatar Feb 18 '25 12:02 jffmarker

Basically yes, we're trying produce a powerpoint-esc sort of workflow. These work items are to help make that happen. Here's what that means and a bit of justification.

We're working on drawing production, so let's look at a sheet:

Image

Image

Image source - both come from the same video

Notice a couple things:

  • There are a variety of text elements. Many of them are contained with in a shape whether that's a circle, square, triangle, or cloud.
  • That text has a bit of a buffer around it, or margin.
  • When text overlaps on the drawing, sometimes a background is added for clarity.

What we aim to do is enable users to make things like this.

Some considerations:

  • While the shapes/borders could be an independent element. It would be better if they were part of the text element itself. If for nothing else than logical grouping. It would also help with actions like copy and paste, selection, etc.
  • We could also do something like the dimensions we have. Logically, however, the borders and margins are directly related to the text and nothing else. Our dimenions have other logic for arrows, length, etc., that are not relevant to the text at all.
  • Powerpoint already does this. Their workflow is fairly intuitive, tried, and tested. This is why we're sort of using it as a blueprint.

@Josh-Schifter, am I missing anything or did I get anything wrong?

claudiaareneee avatar Feb 18 '25 14:02 claudiaareneee

PowerPoint has both a "text box" and "shapes" that can have text in them... which one are you trying to mimic?

jffmarker avatar Feb 18 '25 15:02 jffmarker

We are not trying to mimic PowerPoint. Claudia's comments are dead on. This is not a new thing. Think about notes in MicroStation for a moment. It was a Frankenstein that we cobbled together despite the lack of underlying text support. The image shows the different frames supported by notes in MicroStation. There is no reason for Note to be a different element type from Text. In fact, I think it makes things more difficult for users and for developers.

Similar comments for tables. Yes, I can make text inside table cells work well despite lack of underlying support. However, things will fit together easier if I can rely on the text to position itself within the table cell, rather than having to do it in the table code.

We have an opportunity now for text to natively support frames, rather than tacking them on as an afterthought.

Image

Josh-Schifter avatar Feb 18 '25 15:02 Josh-Schifter

A Note in MicroStation consists of three elements, Frame, Text, and Leader. My hope is that we have good enough support in text that we can combine Frame and Text into a single element type. Honestly, those two interact in a very intimate way as described above.

I've done a lot of thinking about also combining Leaders and I'm not convinced those should be part of the same element. For several reasons I would like to include Leaders, but I'm leaning toward keeping them separate.

Josh-Schifter avatar Feb 18 '25 15:02 Josh-Schifter

Please explain why you consider them redundant. Anchor point is orthogonal to text justification.

As implemented they are orthogonal, however I contend that users will never want a mismatch between them. To understand my point, I think it helps to consider that all text lives inside a rectangle (like a table cell). The anchor point is supposed to specify the most natural point around which to make manipulations. I contend there is no value in making manipulations around a point distant from the text. Example, in the image below, what value is there in rotating this text around the right edge?

Image

Example two, in a table I use the anchor point for 'cell alignment' and it works great for that as long as I always set the justification to match. If I don't, then the results are non-intuitive. I contend users will complain that the first cell looks like it is aligned to the left... it is not.

Image

In MicroStation, to avoid this I take the justification from the text editor and use it to override the alignment of the cell. In fact, I literally just reproduced a bug caused by the two being in disagreement.

Last argument is that the additional flexibility just adds complexity. Other apps don't allow it. Users don't need it. Why have it?

Josh-Schifter avatar Feb 18 '25 20:02 Josh-Schifter

Proposition:

  1. Remove TextAnnotation.anchor.
  2. Add TextAnnotation.verticalAlignment: "top" | "middle" | "bottom"
  3. Remove TextBlock.justification
  4. Add Paragraph.justification: "left" | "right" | "center" | "justify"

Reasoning:

We want to be able to support multiple justifications within one text block. We honestly don't need to expose an anchor point. All we need is one origin, the width, and the height. I think the original reasoning for having an anchor point was to have a way to set a stationary point that we could attach a leader line to. We do still need this functionality but I propose we do this another way. I don't have a solution, but I think we can do better than what's in microstation.

Image Image

claudiaareneee avatar Feb 18 '25 22:02 claudiaareneee

in the image below, what value is there in rotating this text around the right edge?

Image

Get rid of the extraneous padding on the right-hand side (let the layout routine compute minimum width instead) and I could certainly see the use in having left-justified text rotate about a pivot point on the right edge.

Anchor point in general doesn't seem very applicable to text inside table cells as the table is going to control the rotation.

@jffmarker thoughts on removing anchor point and inferring it from vertical/horizontal text alignment?

pmconne avatar Feb 19 '25 13:02 pmconne

Outside the context of tables... what if you want a block of text to be left-justified, but positioned to the left side of an element; you'd want the anchor to be on the right, but justified to the left. How often will someone want this? I dunno... but that would be a reason to have an anchor concept distinct from justification. If you didn't have this concept, the user could place with a left anchor, and then snap to the right edge of the text box to position it if you didn't have this concept. From my Mstn days, the origin / insertion point / anchor point always had special meaning in terms of how to transform text or make it view independent, because it was the only point the user actually interactively placed and had control over. If text is now always in a shape (e.g. box), then the shape is what the user places, not the anchor point... so perhaps the concept is superseded. I guess in summary, distinct anchor gives the most flexibility... but at a complexity cost... given workarounds, perhaps it's not worth it.

jffmarker avatar Feb 19 '25 13:02 jffmarker

The situation Jeff described. Seems reasonable to me.

Image

Josh-Schifter avatar Feb 19 '25 18:02 Josh-Schifter

Anchor point in general doesn't seem very applicable to text inside table cells as the table is going to control the rotation.

Anchor point + margins would be convenient for positioning text within a table cell. All I would need is to specify one of the nine locations around a table cell. That would be drop dead easy. That said, I can also query for the text width and height and then compute whatever origin is required by the API.

For the record, I don't persist the anchor point, it is computed on the fly.

Josh-Schifter avatar Feb 19 '25 19:02 Josh-Schifter

  1. We should remove either TextBlock.justification or TextAnnotation.Anchor.horizontal. They are redundant

@Josh-Schifter have we come to a consensus that we don't want to do this?

  1. Add text frame shape to TextAnnotation2d.

I agree that having the frame be part of the annotation makes sense. I worry about the cmobinatorial explosion of all the different kinds of shapes people are going to want us to support (including custom shapes? stroked line styles? etc?)

pmconne avatar Mar 17 '25 15:03 pmconne

We should remove either TextBlock.justification or TextAnnotation.Anchor.horizontal. They are redundant @Josh-Schifter have we come to a consensus that we don't want to do this?

Yes. When I made that suggestion I was overly focused on tables.

Josh-Schifter avatar Mar 17 '25 17:03 Josh-Schifter

I agree that having the frame be part of the annotation makes sense. I worry about the cmobinatorial explosion of all the different kinds of shapes people are going to want us to support (including custom shapes? stroked line styles? etc?)

Our starting plan is to stick with a smallish set of pre-canned shapes (less than 10). We will vet these shapes with the domain PMs for our initial customers. I would like to defer any work on custom shapes just for practical reasons.

Josh-Schifter avatar Mar 17 '25 17:03 Josh-Schifter

Alright, I've been working on issue #7677 and it has turned into adding frames as well as fill to text annotations. The idea is that frames will be used in combination with leader lines.

I have code that works, but the question is where to put it. So I wanted to open the floor to discussions on it. I have a couple proposals currently.

Proposal 1: Add methods to core/common geometry builders

  • The GeometryStreamBuilder and ElementGeometry.Builder classes have an appendTextBlock method already.
  • We could add a new appendTextAnnotation method that calls:
    • appendTextBlock: existing method, leave this unchanged
    • appendLeaderLine: new method, could be called directly for stand alone leader lines
    • appendFrame: new method, could be called directly for things like tables, etc.
  • Would add the following files to common:
    • TextAnnotationGeometryProps
    • FrameGeometryProps
    • FrameGeometry
    • LeaderLineGeometryProps
    • LeaderLineGeometry
Pros Cons
Fits within existing infrastructure Would add more clutter to the fundamental GeometryStreamBuilder and ElementGeometry.Builder classes
No new paradigms or patters Could explode these basic classes with less generic code
Fairly straightforward

Proposal 2: Add a new ‘stroker’ layer to core

  • The purpose is to combine TextLayoutResult with graphics and reduce calls to the backend. Specifically reducing duplicate calls to:
    • computeLayoutTextBlockResult
    • produceTextAnnotationGeometry
  • This is a layer that currently doesn’t exist in core. We would be introducing a new pattern.
  • In common, we would add a new class: TextAnnotationStroker
  • We would need two versions:
    • ElementGeometry.Builder: called from backend
    • GeometryStream: called wherever
  • TextAnnotationElement and TextDecoration would call this instead of GeometryStreamBuilder
  • We would likely refactor or remove appendTextBlock to require use of the new stroker
  • We will probably need to make similar files listed in Proposal 1 still.
Pros Cons
Would keep GeometryStreamBuilder and ElementGeometry.Builder classes cleaner Introduces a new pattern
Adds more files and boilerplate code

We could do both proposal 1 and 2. Eventually we might want to pull our deminsion code into core. Proposal 2 would be a gateway for adding the stroker pattern that our deminsions use to core.

claudiaareneee avatar Apr 09 '25 19:04 claudiaareneee