VDBRegisterListApplication.st
author Jan Vrany <jan.vrany@labware.com>
Fri, 12 Mar 2021 17:58:59 +0000
changeset 211 2bf7c99e6efa
parent 151 bc7626f46210
child 241 9996050286c5
permissions -rw-r--r--
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> $'
! !