UI: avoid regenerating register list if possible to avoid flickering
This is done by updating presenters in-place when possible instead of
regenerating them. This avoids flickering and also keeps selection
and scroll position.
"
jv:vdb - Visual / VM Debugger
Copyright (C) 2015-now Jan Vrany
Copyright (C) 2021 LabWare
This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'
You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
"
"{ Package: 'jv:vdb' }"
"{ NameSpace: Smalltalk }"
VDBAbstractTreeApplication subclass:#VDBRegisterListApplication
instanceVariableNames:'registerListHolder selectedRegisterHolder'
classVariableNames:''
poolDictionaries:''
category:'VDB-UI-Others'
!
!VDBRegisterListApplication class methodsFor:'documentation'!
copyright
"
jv:vdb - Visual / VM Debugger
Copyright (C) 2015-now Jan Vrany
Copyright (C) 2021 LabWare
This software is licensed under 'Creative Commons Attribution-NonCommercial 4.0 International License'
You may find a full license text in LICENSE.txt or at http://creativecommons.org/licenses/by-nc/4.0/
"
! !
!VDBRegisterListApplication class methodsFor:'accessing'!
defaultWindowTitle
^ self resources string:'Registers'
"Created: / 11-07-2017 / 16:37:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 01-10-2018 / 12:08:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBRegisterListApplication class methodsFor:'interface specs'!
columnsSpec
"This resource specification was automatically generated
by the DataSetBuilder of ST/X."
"Do not manually edit this!! If it is corrupted,
the DataSetBuilder may not be able to read the specification."
"
DataSetBuilder new openOnClass:VDBFrameApplication andSelector:#columnsSpec
"
<resource: #tableColumns>
^#(
(DataSetColumnSpec
label: 'Value'
labelAlignment: left
labelButtonType: Button
width: 1.0
height: heightOfFirstRow
menuFromApplication: false
printSelector: value
backgroundSelector: backgroundColor
showRowSeparator: false
showColSeparator: false
)
)
! !
!VDBRegisterListApplication class methodsFor:'plugIn spec'!
aspectSelectors
"This resource specification was automatically generated
by the UIPainter of ST/X."
"Do not manually edit this. If it is corrupted,
the UIPainter may not be able to read the specification."
"Return a description of exported aspects;
these can be connected to aspects of an embedding application
(if this app is embedded in a subCanvas)."
^ #(
#debuggerHolder
#frameHolder
#registerListHolder
#selectedRegisterHolder
).
"Modified: / 27-09-2018 / 20:32:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 12-03-2021 / 15:44:08 / Jan Vrany <jan.vrany@labware.com>"
! !
!VDBRegisterListApplication class methodsFor:'startup-web applications'!
initialPageSpec
"this is only required for web-applications"
^ self shouldImplement
!
pageSpecs
"this is only required for web-applications"
^ self shouldImplement
! !
!VDBRegisterListApplication methodsFor:'aspects'!
backgroundColorFor: aVDBRegisterPresenter
^ aVDBRegisterPresenter register hasChanged
ifTrue:[ Color yellow lighter lighter ]
ifFalse:[ nil ]
"Created: / 01-02-2018 / 09:08:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified: / 27-09-2018 / 20:41:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
frameHolder: aValueModel
| registers |
registers := (AspectAdaptor forAspect:#registers)
subjectChannel: aValueModel;
yourself.
self registerListHolder: registers
"Created: / 12-03-2021 / 15:43:53 / Jan Vrany <jan.vrany@labware.com>"
!
registerListHolder
"return/create the 'variableObjectListHolder' value holder (automatically generated)"
registerListHolder isNil ifTrue:[
registerListHolder := ValueHolder with: #().
registerListHolder addDependent:self.
].
^ registerListHolder
"Created: / 27-09-2018 / 20:31:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
registerListHolder:something
"set the 'variableObjectListHolder' value holder (automatically generated)"
|oldValue newValue|
registerListHolder notNil ifTrue:[
oldValue := registerListHolder value.
registerListHolder removeDependent:self.
].
registerListHolder := something.
registerListHolder notNil ifTrue:[
registerListHolder addDependent:self.
].
newValue := registerListHolder value.
oldValue ~~ newValue ifTrue:[
self update:#value with:newValue from:registerListHolder.
].
"Created: / 27-09-2018 / 20:31:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
selectedRegisterHolder
"return/create the 'selectedVariableHolder' value holder (automatically generated)"
selectedRegisterHolder isNil ifTrue:[
selectedRegisterHolder := ValueHolder new.
selectedRegisterHolder addDependent:self.
].
^ selectedRegisterHolder
"Created: / 27-09-2018 / 20:31:25 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!
selectedRegisterHolder:something
"set the 'selectedVariableHolder' value holder (automatically generated)"
| oldValue newValue |
selectedRegisterHolder notNil ifTrue:[
oldValue := selectedRegisterHolder value.
selectedRegisterHolder removeDependent:self.
].
selectedRegisterHolder := something.
selectedRegisterHolder notNil ifTrue:[
selectedRegisterHolder addDependent:self.
].
newValue := selectedRegisterHolder value.
oldValue ~~ newValue ifTrue:[
self
update:#value
with:newValue
from:selectedRegisterHolder.
].
"Created: / 27-09-2018 / 20:31:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBRegisterListApplication methodsFor:'change & update'!
update:aspect with:param from:sender
"Invoked when an object that I depend upon sends a change notification."
sender == registerListHolder ifTrue:[
self enqueueDelayedUpdateContents.
^ self.
].
super update:aspect with:param from:sender
"Modified: / 14-02-2019 / 16:31:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBRegisterListApplication methodsFor:'change & update-delayed'!
delayedUpdateInternalList
| registers registerPs mustUpdate |
registers := self registerListHolder value ? #().
registerPs := self internalListHolder root children.
"/ Since set of registers for given inferior is 99% likely to
"/ be the same all the time, here we keep the list of presenters
"/ and only update presenter's register if possible. This avoids
"/ flickering and preserve selection and scroll position.
"/
"/ Still, we have to catch the case the set of registers changes -
"/ this may happen on IBM Cell or when debugging multiple inferiors
"/ each running different architecture.
mustUpdate := registers size ~~ registerPs size.
mustUpdate ifFalse: [
| i |
i := 1.
[ mustUpdate not and: [ i <= registers size ] ] whileTrue: [
(registers at: i) register = (registerPs at: i) register register ifTrue: [
"/ Good, this presenter is for the same register, so just
"/ updates it's value
(registerPs at: i) setRegister: (registers at: i)
] ifFalse: [
"/ Hmm...some other register, we need a full update
"/ (this also short-circuits the loop)
mustUpdate := true.
].
i := i + 1.
]
].
mustUpdate ifTrue: [
"/ Full update is needed, regenerate a list of registers.
registerPs := registers collect:[ :reg | VDBRegisterPresenter new setRegister: reg ].
self internalListHolder root
children: registerPs;
expand.
] ifFalse: [
"/ No full update needed, but some of the values may have changed,
"/ so redraw the list (remember, register values in presenter objects
"/ are already updated, see the loop above).
self delayedInvalidateInternalList.
].
"Modified: / 28-09-2018 / 06:50:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
"Modified (format): / 12-03-2021 / 17:56:34 / Jan Vrany <jan.vrany@labware.com>"
!
delayedUpdateSelection
| internalSelection |
internalSelection := self internalSelectionHolder value.
internalSelection notNil ifTrue:[
self selectedRegisterHolder value: internalSelection register
] ifFalse:[
self selectedRegisterHolder value: nil
].
"Modified: / 27-09-2018 / 21:08:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBRegisterListApplication methodsFor:'drag & drop'!
dropObjects:aCollectionOfDropObjects
"drop manager wants to drop.
This is ony sent, if #canDrop: returned true.
Must be redefined in order for drop to work."
^ self shouldImplement
! !
!VDBRegisterListApplication methodsFor:'event handling'!
onStoppedEvent: aGDBStoppedEvent
self enqueueDelayedInvalidateInternalList
"Created: / 01-02-2018 / 23:14:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBRegisterListApplication methodsFor:'initialization & release'!
subscribe
"Register for debugger events. To be overrided by subclasses"
debugger announcer
when: GDBStoppedEvent send: #onStoppedEvent: to: self
"Created: / 01-02-2018 / 23:07:19 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !
!VDBRegisterListApplication class methodsFor:'documentation'!
version_HG
^ '$Changeset: <not expanded> $'
! !