Dropdown showing wrong data
Closed this issue ยท 24 comments
I have a dropdown declared like this:
dropdown_
selectedKeys
(map (\k -> Just k) (model ^. keys))
currentKeysTree
currentKeysTree
[ onChange KeysSelected ]
`styleBasic` [ width 400 ]
Further there is a possibility to add more keys to model.keys
. If a new entry is added, the dropdown gets longer, but the last element is duplicated in the UI, instead of being rendered correctly.
Using Debug.Trace proves the data in model.keys
seems to be correct.
Start point (only one element):
[Just ("2970232b2c4a65ed3ab853fbbf54b894277a5236124480dea67b81e30da94b44749385522b940654ab1bdf69358e10a48c546182614eeb650fb09b6c87de82e32013bc3efa885efe545e3432498d834aaf4db2f0ff3f37c65389557432365c0e","e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374",True)]
The value e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374
is rendered correctly in the dropdown.
One more element added:
[Just ("db1b173fbc7d0c3fdc15d39b663e0b5535f61e4d41cb228fd337317da2ca2853c645209e2e99deb17736d92c68a38c94a49dfc85d1d6a1d0e2c7354b5d995fe2a4362ea8c002cfe5d5db2967da7127670ab946142405edf46212bc88679be804","e25f995d4b35c7e2d0a1d6d185fc9da4948ca3682cd93677b1de992e9e2045c6",True),Just ("2970232b2c4a65ed3ab853fbbf54b894277a5236124480dea67b81e30da94b44749385522b940654ab1bdf69358e10a48c546182614eeb650fb09b6c87de82e32013bc3efa885efe545e3432498d834aaf4db2f0ff3f37c65389557432365c0e","e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374",False)]
Two elements e25f995d4b35c7e2d0a1d6d185fc9da4948ca3682cd93677b1de992e9e2045c6
and e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374
rendered correctly.
Third element added:
[Just ("a9515fef92866221e144b17ea32cd8c5be2338e306c834be470b5b4216d03dcc80bb04c1e5039ec23e1f5f951a145d6dd4a39ab76f6a95f2e4c5505d51e749110f60e6b7a26fddff3ee9cae0ebb670d053e3da4d5b854e5e6f310706f5b8290b","1149e7515d50c5e4f2956a6fb79aa3d46d5d141a955f1f3ec29e03e5c104bb80",True),Just ("db1b173fbc7d0c3fdc15d39b663e0b5535f61e4d41cb228fd337317da2ca2853c645209e2e99deb17736d92c68a38c94a49dfc85d1d6a1d0e2c7354b5d995fe2a4362ea8c002cfe5d5db2967da7127670ab946142405edf46212bc88679be804","e25f995d4b35c7e2d0a1d6d185fc9da4948ca3682cd93677b1de992e9e2045c6",False),Just ("2970232b2c4a65ed3ab853fbbf54b894277a5236124480dea67b81e30da94b44749385522b940654ab1bdf69358e10a48c546182614eeb650fb09b6c87de82e32013bc3efa885efe545e3432498d834aaf4db2f0ff3f37c65389557432365c0e","e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374",False)]
expected elements to be rendered:
1149e7515d50c5e4f2956a6fb79aa3d46d5d141a955f1f3ec29e03e5c104bb80
, e25f995d4b35c7e2d0a1d6d185fc9da4948ca3682cd93677b1de992e9e2045c6
and e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374
.
actual elements being rendered:
1149e7515d50c5e4f2956a6fb79aa3d46d5d141a955f1f3ec29e03e5c104bb80
, e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374
and e382de876c9bb00f65eb4e618261548ca4108e3569df1bab5406942b52859374
.
For each further element this goes on and on.
I replaced (map (\k -> Just k) (model ^. keys))
with (trace (show (map (\k -> Just k) (model ^. keys))) (map (\k -> Just k) (model ^. keys)))
to get some debug output, the data seems to be correct, but the dropdown renders wrong content. The element itself seems to be correct though, the correct element is getting selected (using onChange), but the display text is wrong.
Do you have a complete example I can use for testing? If it is a single file, you can paste it here. You can format it with Haskell colors if you use:
```haskell
your code here
```
try this:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}
module Main where
import Control.Lens
import Data.Text (Text, pack)
import Monomer
import Monomer.Widgets.Single
type AppWenv = WidgetEnv AppModel AppEvent
type AppNode = WidgetNode AppModel AppEvent
data AppModel =
AppModel
{ _fields :: [Text]
, _current :: Int
, _currentField :: Text
}
deriving (Eq, Show)
data AppEvent
= AppInit
| AddField
| FieldSelected Text
deriving (Eq, Show)
makeLenses 'AppModel
handleEvent
:: AppWenv
-> AppNode
-> AppModel
-> AppEvent
-> [AppEventResponse AppModel AppEvent]
handleEvent wenv node model evt =
case evt of
FieldSelected f ->
[ Model $ model
& currentField .~ f
]
AppInit ->
[]
AddField ->
[ Model $ model
& fields .~ newField : oldFields
& current +~ 1
] where
newField = pack ("Text_" ++ show (model ^. current))
oldFields = model ^. fields
buildUI :: AppWenv -> AppModel -> AppNode
buildUI wenv model = widgetTree
where
widgetTree =
vstack
[ hstack
[ filler
, dropdown_
currentField
(model ^. fields)
currentFieldNode
currentFieldNode
[ onChange FieldSelected ]
`styleBasic` [ width 400 ]
, spacer
, button "Add" AddField
] `styleBasic` [ paddingL 10, paddingR 10]
] `styleBasic` [height 20]
currentFieldNode :: Text -> AppNode
currentFieldNode t = label t
main :: IO ()
main = do
startApp model handleEvent buildUI config
where
config =
[ appWindowTitle "Monomer Bug"
, appTheme darkTheme
, appFontDef "Regular" "./assets/fonts/Roboto-Regular.ttf"
, appInitEvent AppInit
]
model = AppModel ["Test_0"] 1 "Test_0"
Just hit the "Add" button a few times and see what's in the dropdown
Somehow related:
I continued some work on the project today and updated the function currentKeysNode
(aka currentFieldNode
in the example above) like this:
currentKeysNode :: [ReceivedEvent] -> Maybe Keys -> AppNode
currentKeysNode res mks = case mks of
Just ks ->
label $ profileName res (snd' ks)
Nothing ->
label ""
profileName function:
profileName :: [ReceivedEvent] -> XOnlyPubKey -> Text
profileName res xo =
maybe (pack $ exportXOnlyPubKey xo) pdName (profileDataFromReceivedEvents res xo)
Dropdown is defined like this:
dropdown_
selectedKeys
(map (\k -> Just k) (model ^. keys))
(currentKeysNode (model ^. receivedEvents))
(currentKeysNode (model ^. receivedEvents))
[ onChange KeysSelected ]
`styleBasic` [ width 400 ]
As you can see, currentKeysNode is used twice, for the header as well as the list.
Now look at the output:
The header shows correct data (aka pdName (profileDataFromReceivedEvents res xo)
), the dropdown shows the fallback (aka pack $ exportXOnlyPubKey xo
. How is this even possible?
There was a bug in selectList
(which is used by dropdown
) that would ignore WidgetRequest
s made by child widgets.
The label
widget recalculates its text glyphs during resize
, and since its WidgetResize
request was being ignored, the label showed stale glyphs. You can check that the data was still correct by resizing the window; that would cause all widgets to resize, and labels would show the correct values.
You can test the fix by modifying your stack.yaml
to point to:
- git: https://github.com/fjvallarino/monomer.git
commit: 6dff90b4ddf9f61bd8634c754378c99df0f246ac
Please let me know if it fixes the problem. Thanks!
No actually it makes it worse.
It now shows the same values for all select-able options.
Ok I take this back, that is shows same values is a problem on my side, I reverted my latest commit and this is no more. But it still shows the fallback only in the dropdown, while it renders the correct value in the header.
I tested with your example. If I add 3/4 items and open the dropdown with the new version, the values it shows are correct. If I revert to the previous version, it shows incorrect labels.
Could you test with the example you provided initially? It's hard to validate when we're testing different versions since unrelated things could be happening. Otherwise, please provide the same example you're testing with.
Maybe running stack clean
or stack purge
to ensure you're using the latest commit can help.
I just received this upon stack run
:
X Error of failed request: BadValue (integer parameter out of range for operation)
Major opcode of failed request: 152 (GLX)
Minor opcode of failed request: 3 (X_GLXCreateContext)
Value in failed request: 0x0
Serial number of failed request: 101
Current serial number in output stream: 102
Nothing changed related to GL context handling in the last several commits, particularly compared to the version you were using previously. That looks like an issue on your machine.
Restart the computer solved it.
I can confirm that the example I provided is fixed now. However it's not for my project. Trying to get more information.
If you can share it somehow, I can take a look.
Sure if you have the time. You'd need however a bit more than "only" haskell, you also would need to compile a C lib from source.
If you think the library is necessary, I can try to build it in a Linux VM.
If you think that library is not essential for the issue we're investigating, and replacing that invocation with some mock would be good enough, it would be better since it's easier for me to test it
Step 1:
git clone https://github.com/bitcoin-core/secp256k1
cd secp256k1
./autogen.sh
./configure --enable-module-schnorrsig --enable-module-extrakeys --enable-module-ecdh --enable-experimental
make
sudo make install
Step 2:
git clone https://github.com/prolic/FuTr.git
cd FuTr
stack run
In the top right corner you can add new keys, with the edit button you can set a profile name. Try switching between profiles and adding new ones.
I also attached a screen recording.
pl-next-2022-05-17_17.52.17.mp4
I do totally understand if you don't have the time to look into my mess, let me know and I try to provide another example, would take me a while though.
I think the problem is caused because the data you store as the list of keys does not really change; what changes is the name you retrieve from those keys. The selectList
widget, used internally by dropdown
, does not refresh its content if the items you provide have not changed. Since
type Keys = (KeyPair, XOnlyPubKey, Bool
did not change, it does not call your function for regenerating the internal nodes.
There are two options:
- You can store the name of the
Keys
once you retrieve it (updating the list). That would trigger the dropdown update. - Use
mergeRequired
to force the dropdown to always update itself.
The problem with the second alternative is I forgot to export this configuration option from dropdown
(it is available in selectList
). I'll add it now and test (I'll let you know how it goes), but I still think the first option is preferable. These widgets (dropdown
and selectList
) avoid updating their content for performance reasons; if you have a long list of items, you'd be incurring a performance penalty that can be avoided by keeping all the data you need for rendering in your model.
An unimportant suggestion: you can use lenses to access arbitrarily sized tuples, with tuple ^. _5
retrieving the fifth element independently of the tuple's size (up to 10, I think).
The application looks very nice! It's great that you created custom widgets for rendering UI decorations ๐
You can store the name of the Keys once you retrieve it (updating the list). That would trigger the dropdown update.
That's something I am working on at the moment.
An unimportant suggestion: you can use lenses to access arbitrarily sized tuples, with tuple ^. _5 retrieving the fifth element independently of the tuple's size (up to 10, I think).
That's awesome, however I am about to refactor the keys to this:
data Keys = Keys KeyPair XOnlyPubKey Bool
deriving (Eq, Show)
I might just add the profile name here.
The application looks very nice!
Really? I hate it, but UI improvements are not my highest priority at the moment, I am working on profile and followers at the moment.
That's awesome, however I am about to refactor the keys to this:
Nice!
The problem is indeed caused by the data not changing; once you add the name to your Keys
type, it should work fine.
I exported mergeRequired
from dropdown
as part of the PR, although you should not need it in this case.
Thank you very much. I'll keep you posted once I'm done with the changes.
Yes! Works like a charm. Thank you very much.
This has just been merged to main. I'll close the issue. Thanks for reporting!