rexrainbow / phaser3-rex-notes

Notes of phaser3 engine
MIT License
1.21k stars 260 forks source link

Text area: Option for scroller thumb height based on content #257

Closed robinheidrich closed 2 years ago

robinheidrich commented 2 years ago

It would be great if there was an option or something to base the height of the scroller thumb on the content. Like the scrollbars in the browser, whose height is based on the content.

Maybe this can be the new standard and you have to set the height of the thumb yourself if you want it small (as it is now).

rexrainbow commented 2 years ago

rexUI: ScrollablePanel, GridTable, TextArea - Add slider.adaptThumbSize, slider.minThumbSize parameters, to adjust thumb height/width according to ratio of visible child

robinheidrich commented 2 years ago

That is very good! Would it also be possible to add a button at the top and bottom to scroll, like in browsers? Optional of course.

Should I create a new issue for this idea?

rexrainbow commented 2 years ago

How to name these top and bottom buttons (or left and right buttons in horizontal scroll mode)?

robinheidrich commented 2 years ago

In browsers it's just called scrollbar button, maybe there could be a config for buttons and inside the game objects for each side.

For example something like that:

{
  buttons: {
    top: scene.add.image(0, 0, 'scrollbar-button-top'),
    bottom: scene.add.image(0, 0, 'scrollbar-button-bottom'),
  },
  ...
}
rexrainbow commented 2 years ago

Might merge buttons.top to topButton to put configuration in the same level.

{
    slider: {
        track: trackGameObject,
        thumb: thumbGameObject,
        topButton: topButtonGameObject,
        bottomButton: bottomButtonGameObject
    },
}

My concern is, there have horizontal and vertical scroll modes.

robinheidrich commented 2 years ago

It would perhaps make more sense to include a separate option for left and right as well?

Maybe you could also just call it top, bottom, left and right if that's not too confusing.

rexrainbow commented 2 years ago

I see, that would be a good solution, too. Or using slider.buttons: []?

{
    slider: {
        track: trackGameObject,
        thumb: thumbGameObject,
        buttons: [buttonGameObject, buttonGameObject],
    },
}

Will the amount of buttons only be 2?

robinheidrich commented 2 years ago

I don`t know, is it possible with Text area to scroll horizontally and vertically at the same time?

But I also thought about making slider.buttons an object.

{
    slider: {
        buttons: {
            top: topButtonGameObject,
            bottom: bottomButtonGameObject
        }
    }
}
rexrainbow commented 2 years ago

rexUI: ScrollablePanel, GridTable, TextArea - Add

Press these buttons to scroll content in each tick. Demo

robinheidrich commented 2 years ago

Looks pretty good so far. Thanks for the implementation!

I noticed something else, and that is that the text is higher than the textarea and if you disable textMask, you can see the text there.

Is that intentional?

image

rexrainbow commented 2 years ago

Yes, it is design intent. The extra line can make content scrolling more smoothly.

robinheidrich commented 2 years ago

It just feels weird because the text is below the slider and the same on top.

I don't know if it's because I disabled textMask, but it doesn't look very smooth either. One line always disappears at a time when scrolling instead of just showing part of the text.

rexrainbow commented 2 years ago

Ah, that's why textarea has a mask of text game object, or using header and footer game object to hide these extra area.

It is possible to create a scrollable text-area without mask, only drawing on canvas. I had made it in phaser4's bbcodetext class. (demo).

robinheidrich commented 2 years ago

That looks better already. But Phaser 4 is still in early development, isn't it?

Also, I prefer the syntax of Phaser 3, so I'm not sure yet if I'll upgrade to Phaser 4 later.

rexrainbow commented 2 years ago

Update:

Cropping text game object when textMask is set to false. Default is false (won't have a mask by default)

robinheidrich commented 2 years ago

Seems a bit smoother, but new lines at the bottom are still cut off when scrolling and are only visible as a whole.

If that would be possible to make it like the top, it would be perfect.

rexrainbow commented 2 years ago

Seems a bit smoother, but new lines at the bottom are still cut off when scrolling and are only visible as a whole.

Could you post a snapshot about this case?

robinheidrich commented 2 years ago

I have now tried a different font and it works, seems to have been due to the font.

Here with a different font where it cuts off at the bottom when scrolling:

capture

rexrainbow commented 2 years ago

I see, that's weird. The last line disappears some time. What kind of font in this case?

robinheidrich commented 2 years ago

This is Burbank Small. It's not a problem, because I need Verdana anyway, but maybe there is a solution for this anyway?

robinheidrich commented 2 years ago

I guess it's not the font after all, but the font size. In the Textarea example change text object to this:

text: this.rexUI.add.BBCodeText(0, 0, '', { fontSize: '24px' })

capture

rexrainbow commented 2 years ago

It also depends on browser:

In firefox: 圖片

In chrome: 圖片

robinheidrich commented 2 years ago

I also use Chrome.

I noticed another thing: Area in BBCode text does not work when mouseWheelScroller.focus is set to true. Is this intentional? So far it only did not work when scroller was on true but not that.

rexrainbow commented 2 years ago

mouseWheelScroller.focus: true will invoke gameObject.setInteractive().on('wheel', ...) reference. It has topOnly issue, too, because that target game object of mouse wheel is not text game object.

rexrainbow commented 2 years ago

Update: TextArea, displays more 1 line to fix scrolling smooth issue.

robinheidrich commented 2 years ago

Looks fine. So is it not possible that areas work when mouseWheelScroller.focus is true?

By the way, there is a typo in the path of MouseWheelScroller: plugins/input/mousewheeldcroller

rexrainbow commented 2 years ago

Set topOnly to false will allow multiple input targets, textarea and mouse wheel scroller both.

rexrainbow commented 2 years ago

Typo fixed, thanks for these suggestions

robinheidrich commented 2 years ago

Unfortunately, this is not a solution either, because area is then always clickable, even if there is a UI element above it.

I think then I have to disable the mouse scrolling for now.

rexrainbow commented 2 years ago

It seems that you have multiple stacked ui windows. There are some solutions for this case.

  1. Modal promise, reference
    scene.rexUI.modalPromise(gameObject, config)
        .then(function(closeEventData){ })
  2. Cover, which is a part of Modal. Put this game object behind background of ui window.
    var shape = scene.rexUI.add.cover(config);
  3. TouchEventStop behavior, which is a part of Cover. Put this behavior to background of ui window.
    var touchEventStop = scene.rexUI.add.toucheventstop(gameObject, config);
robinheidrich commented 2 years ago

I don't think that's a solution either, because I don't want to block the whole background.

Is there no way that the events could only be extended and not overwritten?

rexrainbow commented 2 years ago

Don't have solution yet. In this case :

robinheidrich commented 2 years ago

@rexrainbow Instead of setting setInteractive on the game object, wouldn't it be possible to just check in the callback if the mouse pointer is over the game object?

So that mouseWheelScroller.focus works with multiple inputs?

rexrainbow commented 2 years ago

You can get mouse-wheel event via

scene.input.on('wheel', function(pointer, currentlyOver, dx, dy, dz, event){ /* ... */ });

It does not interactive with game object. Under this event, test if mouse cursor is inside scrollable panel via

var isTouching = scrollablePanel.isInTouching();
robinheidrich commented 2 years ago

I was talking about this particular section of code, if this were changed to always use the callback and instead check in the callback if the mouse pointer is over the game object instead of using setInteractive, mouseWheelScroller.focus would work without topOnly or other workarounds, wouldn't it?

rexrainbow commented 2 years ago

These 2 solutions have a little different. For example, a big game object puts above scrollable panel. scrollablePanel.isInTouching() will still return true if pointer is inside the bounds of scrollable panel. But gameObject.on('wheel', ...) won't be fired, if topOnly is true. Because that only the top game object will receive touch events.