Cards controls loop?

LiveCode is the premier environment for creating multi-platform solutions for all major operating systems - Windows, Mac OS X, Linux, the Web, Server environments and Mobile platforms. Brand new to LiveCode? Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

dunbarx
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 10305
Joined: Wed May 06, 2009 2:28 pm

Re: Cards controls loop?

Post by dunbarx » Mon Aug 12, 2024 5:28 am

Regarding those trees that fill the forest.

I use the "Find and Replace" gadget constantly. It allows me to identify the one or more objects that contain the string of interest. One can navigate to those objects one by one, and using the SE find tools, locate the string's occurrences one by one.

But that is not always what I need, and I believe the OP wants something rather different as well. He asked for all occurrences of a string everywhere. Not just which objects contain it, but where they are in every place that they are.

That is why I never thought of suggesting "Find and Replace...", rather to go down the path of creating a "look everywhere" procedure that would identify all the string "locations" everywhere. My offering, from HC days, was woefully inadequate, but did suggest the method of navigating through all possible string-containing objects. That old gadget missed groups, of course.

Anyway, that is the right method, and a really good implementation would return something like the OP originally posted, a list of all objects that contain the string, along with all its locations within each script, as well as perhaps a few lines before and after the string for context.

Craig

Zax
Posts: 519
Joined: Mon May 28, 2007 10:12 am
Contact:

Re: Cards controls loop?

Post by Zax » Mon Aug 12, 2024 6:52 am

With all your ideas and different tests, here is what I finally did. It is not necessarily the fastest solution - and the script can probably be optimized - but it meets my different needs.

Code: Select all

function getStackControlList pStackName
   /*
   return a tab-cr delimited list of all controls of passed stack and its sub-stacks
   one line per control with data separated by tab
   1 - control kind ("stack", "group", "card", "button", ...)
   2 - control short name
   3 - control short ID
   4 - owner stack short name
   5 - owner main stack short name (same as #4 if the searched stack is a main stack)
   6 - owner card short name (or empty if not available)
   
   return empty if passed stack not exists
   */
   
   local controlsList
   if (pStackName <> "") then controls_stacks controlsList, pStackName
   return controlsList
end getStackControlList

private command controls_stacks @controlsList, mainStackName
   if (there is a stack mainStackName) then
      ---------------------------------- main stack
      controls_inStack controlsList, mainStackName
      ---------------------------------- sub stacks
      repeat for each line thisSubStackName in the substacks of stack mainStackName
         controls_inStack controlsList, thisSubStackName
      end repeat
   end if
end controls_stacks

private command controls_inStack @controlsList, stackName
   // update controlsList with all controls of passed stack
   ---------------------------------- passed stack
   controls_updateResult controlsList, stackName, "", the long id of stack stackName
   ---------------------------------- cards of passed stack
   local cardLongId, cardName
   repeat with c = 1 to (the number of cards in stack stackName)
      put the short name of card c of stack stackName into cardName
      ---------------- cards
      put the long id of card c of stack stackName into cardLongId
      controls_updateResult controlsList, stackName, cardName, cardLongId
      ---------------- cards controls (including groups)
      repeat with n = 1 to (the number of controls in cardLongId)
         controls_updateResult controlsList, stackName, cardName, the long id of control n of cardLongId
      end repeat
   end repeat
end controls_inStack

on controls_updateResult @controlsList, @stackName, cardName, controlLongId
   // update controlsList : one line per control, with data separated by tab
   // 1 - kind      2 - name      3 - ID      4 - stack name      5 - mainStack name      6 - card name
   get word 1 of controlLongId & tab & the short name of controlLongId & tab & the id of controlLongId & tab & \
         stackName & tab & the mainStack of stack stackName & tab
   if (it is not in controlsList) then put it & cardName & cr after controlsList
end controls_updateResult
For searching for occurrences in the scripts of the controls, the globalMatch() function presented by Stam can be interesting as it allows to search with regex:
https://github.com/stam66/regexPrimerFo ... workaround

In a first try, I used the long IDs of the controls but this is not a good idea in the case where we want to store the sizes and positions of the controls because if the stack is moved, the long IDs will no longer be valid.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Cards controls loop?

Post by bn » Mon Aug 12, 2024 10:51 am

Zax wrote:
Mon Aug 12, 2024 6:52 am
In a first try, I used the long IDs of the controls but this is not a good idea in the case where we want to store the sizes and positions of the controls because if the stack is moved, the long IDs will no longer be valid.
Hi Zax,

You could use the "ruggedID". The IDE has a function that returns the ruggedID

example

Code: Select all

on mouseUp
   put revRuggedID (the long id of control 1 of this card)
end mouseUp
This returns
control id 1006 of stack "testStackZaxScriptSearch"
It has only the ID and the stack name. That also works the other way around:

Code: Select all

put the long id of control id 1006 of stack "testStackZaxScriptSearch"

If you do not want to use the built-in function it is easy to construct a rugged ID on the fly.

Kind regards
Bernd

Zax
Posts: 519
Joined: Mon May 28, 2007 10:12 am
Contact:

Re: Cards controls loop?

Post by Zax » Mon Aug 12, 2024 11:25 am

bn wrote:
Mon Aug 12, 2024 10:51 am
You could use the "ruggedID". The IDE has a function that returns the ruggedID
Interesting! I had noticed the use of ruggedID() in your scripts but I had not looked in detail at what this function did.
Thanks Bernd :)

I'll do some more testing but it seems to me that sometimes the backgroundIDs returns groups that don't appear in the IDE's Project Browser.

bobcole
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 161
Joined: Tue Feb 23, 2010 10:53 pm

Re: Cards controls loop?

Post by bobcole » Mon Aug 12, 2024 2:45 pm

I couldn't find revRuggedID() in my Dictionary.
Bob

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Cards controls loop?

Post by bn » Mon Aug 12, 2024 2:49 pm

bobcole wrote:
Mon Aug 12, 2024 2:45 pm
I couldn't find revRuggedID() in my Dictionary.
Bob
Hi Bob,

That is because it is part of the IDE, it is located in stack "revcommonlibrary".

Kind regards
Bernd

bobcole
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 161
Joined: Tue Feb 23, 2010 10:53 pm

Re: Cards controls loop?

Post by bobcole » Mon Aug 12, 2024 2:52 pm

bernd:
Okay, thanks.
Bob

stam
Posts: 3060
Joined: Sun Jun 04, 2006 9:39 pm

Re: Cards controls loop?

Post by stam » Mon Aug 12, 2024 2:58 pm

as far as I can tell, it returns a generic "control id xx of <stack>", instead of a long id. The id is the same, just abstracted to 'control' instead of the specific control type (eg 'button', 'field', etc). Not sure this is any different from simply storing the id?

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Cards controls loop?

Post by bn » Mon Aug 12, 2024 3:09 pm

stam wrote:
Mon Aug 12, 2024 2:58 pm
as far as I can tell, it returns a generic "control id xx of <stack>", instead of a long id. The id is the same, just abstracted to 'control' instead of the specific control type (eg 'button', 'field', etc). Not sure this is any different from simply storing the id?
Hi Stam,

Zax worried about the long ID being dependent on the file name and location.

Rugged ID (control id xxx of stack "yz") does is not dependent on file name and location and is unique and can be transformed into other forms of reference to objects.
LC uses it to reference behaviours for pretty much the reasons described above.

Nothing more, nothing less.

Kind regards
Bernd

stam
Posts: 3060
Joined: Sun Jun 04, 2006 9:39 pm

Re: Cards controls loop?

Post by stam » Tue Aug 13, 2024 1:56 am

bn wrote:
Mon Aug 12, 2024 3:09 pm
Zax worried about the long ID being dependent on the file name and location.
I only just noticed this but at first glance it loos like subStacks don't have a separate ID?
Seems to be 1002 for all subStacks, the same as any new stack -- is this right?

revRuggedID returns the name of the stack, so since there is no id to rely on, this definitely seems useful... learned something new again ;)

Zax
Posts: 519
Joined: Mon May 28, 2007 10:12 am
Contact:

Re: Cards controls loop?

Post by Zax » Tue Aug 13, 2024 6:48 am

stam wrote:
Tue Aug 13, 2024 1:56 am
I only just noticed this but at first glance it loos like subStacks don't have a separate ID?
Seems to be 1002 for all subStacks, the same as any new stack -- is this right?
Very interesting point!

I just reread the Dictionary and, when it says "For all objects, the ID is guaranteed to be unique within a stack", I think that it means "stack" in the strict sense of the term: a substack is a stack. I hadn't paid attention to that and I thought that an ID was unique for a stack and all its substacks.

Reading the Dictionary also allowed me to rediscover "the abbreviated id" which corresponds for example to "field id 1365".

stam
Posts: 3060
Joined: Sun Jun 04, 2006 9:39 pm

Re: Cards controls loop?

Post by stam » Tue Aug 13, 2024 8:44 am

But here is where revRuggedID() is probably better. As the ID is only guaranteed to be unique within a single stack, you cannot key an array to the ID in more than one stack - eg substacks - and maintain unique identifiers.

Let alone if you wanted to make a script that checked a project instead of a stack, which would mean also including library stacks and front/backscripts where these are stacks as well.

Sounds complicated but probably much less than appears.

Zax
Posts: 519
Joined: Mon May 28, 2007 10:12 am
Contact:

Re: Cards controls loop?

Post by Zax » Tue Aug 13, 2024 11:14 am

stam wrote:
Tue Aug 13, 2024 8:44 am
But here is where revRuggedID() is probably better. As the ID is only guaranteed to be unique within a single stack, you cannot key an array to the ID in more than one stack - eg substacks - and maintain unique identifiers.
Right.

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4163
Joined: Sun Jan 07, 2007 9:12 pm

Re: Cards controls loop?

Post by bn » Tue Aug 13, 2024 11:24 am

Hi all,

Due to popular demand (N=1) I post an improved version of "SearchScripts"

Changes:
all entries are shown by ID (previously I had a mix of IDs and names and card number, especially card number would be invalid of cards are sorted after running "SearchScripts)
controls are sorted by layer.
cards are sorted by position in stack
background groups are reported for the first card where they are placed (previously last occurrence)
A tooltip shows the long name of an entry.

As before click on a line in the display field to go to first occurrence of search term in the script, if more than one occurrence click on the trailing numbers.

Some cleanup.

Kind regards
Bernd
Attachments
searchScripts_04_BN.livecode.zip
(3.38 KiB) Downloaded 293 times

stam
Posts: 3060
Joined: Sun Jun 04, 2006 9:39 pm

Re: Cards controls loop?

Post by stam » Tue Aug 13, 2024 11:33 am

Thanks Bernd, will definitely look at your solution.
I have not yet seen your solution, as was writing my own as an interesting mental exercise ;)
But I've not implemented this as a search, just as a way to create an array with all objects and their scripts.

I moved this from stack level to project level, meaning I look at all stacks, subStacks, stacksInUse, frontScripts and backScripts, excluding IDE stacks and stacks residing in Plugins/Extensions folders. I have no use for this directly at present, but was an interesting exercise. At the very least, it's a way to count the number of lines in my apps!

This script returns an array that is keyed to the revRuggedID() of each object that can contain a script:

Code: Select all

function analyseStacks
    local tStackLongID, tSubStacks, tStackList, tObjectListA
    put the stacks into tStackList
    _removeIDEstacks tStackList
    repeat for each line tStack in tStackList
        put the long id of stack tStack into tStackLongID
        getObejcts the long id of stack tStack, tObjectListA
        
        // stacksInUse / Libraries
        put the stacksInUse into tStackList
        _removeIDEstacks tStackList
        repeat for each line tStack in tStackList
            getObejcts the long id of stack tStack, tObjectListA
        end repeat
        
        // substacks
        put the substacks of tStackLongID into tSubStacks
        repeat for each line tStack in tSubStacks
            getObejcts (revRuggedID(the long id of stack tStack of tStackLongID)), tObjectListA
        end repeat
        
        // front and backscripts
        put the frontScripts into tStackList
        put return & the backScripts after tStackList
        _removeIDEstacks tStackList
        repeat for each line tStack in tStackList
            if word 1 of tStack is "stack" then getObjects the long id of stack tStack, tObjectListA
        end repeat
    end repeat
    
    //return array with all objects that can have scripts and their scripts
    return tObjectListA
end analyseStacks
the helper command to exclude IDE/Plugin/Extension stacks from lists passed by reference:

Code: Select all

private command _removeIDEstacks @pStackList -- remove IDE or plugin/extension stacks
    filter pStackList without "*/Extensions/*"
    filter pStackList without "*/Plugins/*"
    filter pStackList without "*/tools/toolset/*"
    filter pStackList without "*/tools/ext/*"    
    filter pStackList without empty
    // can add a line to exclude this script if implemented as a library for example
end _removeIDEstacks
The first script passes a stack to a 2nd command by reference, which then processes stacks/cards/objects and adds to the array:

Code: Select all

command getObejcts stackRuggedID, @pObjectListA -- build array with objects & scripts of each stack
    local tStack, tCard, tControlID, tCardIDs
    //stack
    put stackRuggedID  into tStack
    put the long name of stackRuggedID into pObjectListA[tStack]["longOwner"]
    put the short name of stackRuggedID into pObjectListA[tStack]["owner"]
    put the script of stackRuggedID into pObjectListA[tStack]["script"]
    //cards
    put the cardIDs of tStack into tCardIDs
    repeat for each line tCardID in tCardIDs
        put revRuggedID(the long id of card id tCardID of tStack) into tCard
        put the long id of tCard into pObjectListA[tCard]["longOwner"]
        put the short name of tCard into pObjectListA[tCard]["owner"]
        put the script of tCard  into pObjectListA[tCard]["script"]
        // controls
        repeat with y = 1 to the number of controls of tCard
            put revRuggedID(the long id of control y of tCard) into tControlID
            put the long id of tControlID into pObjectListA[tControlID]["longOwner"]
            put the short name of tControlID into pObjectListA[tControlID]["owner"]
            put the script of tControlID into pObjectListA[tControlID]["script"]
        end repeat
    end repeat
end getObejcts
seems to work fine (and in a small test stack, very quickly, but not tested large complex solution yet).
I used a tree control to visualise the results.
I would envisage a search function being filtering this array by the ["script"] key to generate a list - but I'm sure your solution is probably quite a lot faster...

For now this is just a mental exercise for me, but any suggestions to improve would be gratefully received...

Stam

Post Reply