Error playing a frame for the third time - actionscript

I have a flash file where the first frame contains two buttons, one of which takes the user to the second frame, and the other takes them to the third frame. At each of those frames, various text fields and variables can be manipulated via SimpleButtons. Both Frame 2 and Frame 3 have "back" buttons to take them back to Frame 1.
Currently when the user navigates back to Frame 1 for the second time (thus playing it for a third time), my second button appears to no longer exist, and I receive an error. Both buttons on Frame 1 were placed via the Flash IDE. Why is my button popping out of existence, when it did perfectly fine the previous two times? Below is my code for Frame 1. The "back" buttons simple remove event listeners and then call gotoAndStop(1)
var inited:Boolean;
var cache:SharedObject;
var libsans:Font = new libsansreg();
this.addEventListener(Event.ENTER_FRAME, frameEnter);
stats.addEventListener(MouseEvent.CLICK, statsclicked);
modules.addEventListener(MouseEvent.CLICK, modsclicked);
function initcache():void
{
this.cache = SharedObject.getLocal("RPG_Shooter")
}
function frameEnter(e:Event):void
{
if (!inited)
{
inited = true
initcache()
this.gotoAndStop(1)
}
}
function statsclicked(e:MouseEvent):void
{
this.removeEventListener(Event.ENTER_FRAME, frameEnter)
stats.removeEventListener(MouseEvent.CLICK, statsclicked)
modules.removeEventListener(MouseEvent.CLICK, modsclicked)
this.gotoAndStop(2)
}
function modsclicked(e:MouseEvent):void
{
this.removeEventListener(Event.ENTER_FRAME, frameEnter)
stats.removeEventListener(MouseEvent.CLICK, statsclicked)
modules.removeEventListener(MouseEvent.CLICK, modsclicked)
this.gotoAndStop(3)
}

I actually had similar problem at one point. It has to do with garbage collection which is not the best in Flash to begin with, but the IDE's compiler settings make it so much more insane. There are a couple of tricks you can try which might help.
Make sure you remove all listeners before leaving the frame.
Go to a "blank" frame (something which still has a background and styling, but no interact-able components) for even a 5/1000 of a second
Set the variable names to "null" on frame one (so if your component on frame 3 is named "foo" put foo = null on frame one)
put var foo:MovieClip on frame 1. repeat for all MovieClips which you might be using that are named ahead of time.

Related

Vaadin's SplitLayout.setSplitterPosition(80) only works the first time; subsequent calls do not seem to respond

In Vaadin 12, I have created a button which, when clicked, sets the split layout position to some non-zero, non-100 value, as shown below:
btnHelp.addClickListener(event -> {
log.info("info pressed");
MainApp.sp.setSplitterPosition(80);
MainApp.iFrameHelp = new Html( "<iframe src=\"https://docs.readthedocs.io/en/latest/intro/getting-started-with-sphinx.html/intro/getting-started-with-sphinx.html\"></iframe>");
//btnHelp.setIcon(new Icon(VaadinIcon.INFO_CIRCLE));
});
This works great. However, if I pretend to be a user and, via the Chrome browser, I adjust the split layout (by dragging the vertical layout) such that I "close" (or just reduce the size of) the second vertical "panel", and THEN I click on the button again, it does NOT seem to obey the command to reset the splitter position to 80. It only seems to obey the command on the first call. Is this a bug? If so, is there a workaround? (Or, should I do this differently?)
This is a side effect of https://github.com/vaadin/vaadin-split-layout-flow/issues/50. What happens is basically that the server-side still believes that the split position is set to 80 which makes it ignore the setSplitterPosition(80) call.
You can work around this by using low-level APIs to set the position in a way that bypasses the server's dirty checking logic:
MainApp.sp.getPrimaryComponent().getElement().executeJavaScript(
"this.style.flexBasis='80%'");
MainApp.sp.getSecondaryComponent().getElement().executeJavaScript(
"this.style.flexBasis='20%'");

Scroll bar in LibreOffice dialog

I am trying to make an image picker component in LibreOffice.
I have a dialog that is dynamically filled with images. When the user clicks on one images, it should be selected and the dialog should be closed.
The problem is that the number of images is variable. So I need to enable scrolling in the dialog (so that the user can navigate through all images).
There seems to be some properties on the dialog object (Scrollbars, Scroll width, Scroll height, etc)
However, I cannot find a way to use them anywhere.
Any ideas?
The scrollbar is one of the Controls available through the dialog box editor. That is the easier way to put a ScrollBar on a dialog box. Just insert it like any other control. There is a harder way via DialogModel.addControl but that seems non-essential to answering this question.
If you add a scrollbar to the dialog box and run the dialog box, you will find it does nothing by default. The functionality (apparently) must be written into a macro. The appropriate triggering event is the While Adjusting event on the ScrollBar object, although it does not trigger the macro simply with the "Test Mode" function in the dialog editor. Running the dialog box through a macro triggers the While Adjusting event when the scroll arrows are triggered, when the slider area is clicked to move the slider, and when the slider itself is dragged. The Object variable returned by the scrollbar event contains a property .Value which is an absolute value between 0 and the EventObject.Model.ScrollValueMax, which allows you to manipulate the other objects on the page manually based on the position of the slider.
Yes, that's right, manipulate objects manually. The sole example I found, from the LibreOffice 4.5 SDK, does precisely this. Of course, it is not as bad as it sounds, because one can iterate through all of the objects on the page by reading the array Dialog.getControls(). In any event, the secret sauce of the example provided in the SDK is to define Static variables to save the initial positions of all of the objects you manipulate with the scrollbar and then simply index those initial positions based on a ratio derived from the scrollbar Value divided by the ScrollValueMax.
Here is a very simple working example of how to scroll. This requires a saved Dialog1 in the Standard library of your document, which contains an object ScrollBar1 (a vertical scrollbar) and Label1 anywhere in the dialog. The ScrollBar1 must be configured to execute the macro ScrBar subroutine (below) on the While Adjusting event. Open the dialog by executing the OpenDialog macro and the scrollbar will move the Label1 control up and down in proportion to the page.
Sub OpenDialog
DialogLibraries.LoadLibrary("Standard")
oVariable = DialogLibraries.Standard.Dialog1
oDialog1 = CreateUnoDialog( oVariable )
oDialog1.Execute()
End Sub
Sub ScrBar (oEventObj As Object)
Static bInit As Boolean
Static PositionLbl1Y0 As Long
oSrc = oEventObj.Source
oSrcModel = oSrc.Model
scrollRatio = oEventObj.Value / oSrcModel.ScrollValueMax
oContx = oSrc.Context
oContxModl = oContx.Model
oLbl1 = oContx.getControl("Label1")
oLbl1Model = oLbl1.Model
REM on initialization remember the position of the label
If bInit = False Then
bInit = True
PositionLbl1Y0 = oLbl1Model.PositionY
End If
oLbl1Model.PositionY = PositionLbl1Y0 - (scrollRatio * oContx.Size.Height)
End Sub
The example provided by the SDK does not run on my setup, but the principles are sound.
There appears to be a second improvised method closer to the functionality one might expect. This method uses the DialogModel.scrollTop property. The property appears to iterate the entire box up or down as a scroll based on the user input. There are two problems using this methodology, however. First, unless you put the scrollbar somewhere else, the scroll bar will scroll away along with the rest of the page. You will need to adjust the location of the scrollbar precisely to compensate for/negate the scrolling of the entire page. In the example below I tried but did not perfect this. Second, the property seems to miss inputs with frequency and easily goes out of alignment/ enters a maladjusted state. Perhaps you can overcome these limitations. Here is the example, relying on the same setup described above.
Sub ScrBar (oEventObj As Object)
Static scrollPos
oSrc = oEventObj.Source
oSrcModel = oSrc.Model
scrollRatio = oEventObj.Value / oSrcModel.ScrollValueMax
If IsEmpty(scrollPos) = False Then
scrollDiff = oEventObj.Value - scrollPos
Else
scrollDiff = oEventObj.Value
End If
scrollPos = oEventObj.Value
oContx = oSrc.Context
oContxModl = oContx.Model
oContxModl.scrollTop = scrollDiff * -1
oSrcModel.PositionY=(scrollRatio * oContx.Size.Height/5) * -1
End Sub
This (sort of) will scroll the contents of the entire dialog box, within limits and with the caveats noted above.

Scaling a TFrame

What is the correct procedure for Scaling a TFrame in C++Builder?
I am developing in PixelsPerInch=120 (aka. Windows font size 125%), but want my forms to work in PixelsPerInch=96 also (aka. default).
My main form loads fine: the VCL code to create a TForm includes a check of whether the design PPI differs from runtime PPI and it scales everything correctly at that point.
However when loading a TFrame, no automatic scaling occurs. So far as I have been able to discover, I have to manually call Frame1->ScaleBy(M, D);.
This mostly works however it has a bug (which I will describe below) so the result is a frame that is not scaled correctly.
What is the proper way to create a Frame and have it scale on load, like a Form does?
I am currently using the following:
// class member
TFrame *f;
// called just before Application->Run()
f = new TFrame(fMain);
int M = fMain->PixelsPerInch;
int D = 120; // Matt's development
if ( M != D )
{
f->ScaleBy(M, D);
}
and then when I want to activate the frame, `f->Parent = fMain->Panel1;
(*f)->ScaleBy(M, D);
I have also tried writing f->Parent = fMain->Panel1; before calling ScaleBy, based on the theory that the Frame has controls using ParentFont and so on, so it might be better if this info is available during scaling; however this introduces other bugs.
The bug is that when calling ScaleBy on a Frame or a Form which has a TLabel which has AutoSize=true and ParentFont=false and Anchors including akBottom, then the Label is displayed much higher up on the window than it should be (maybe even off the top of the window).
I have tracked down the problem: the TControl.ChangeScale function includes a call to ScaleMargins, and the Margin property has an on-set trigger that ends up calling AlignControls for the parent form, which will move any controls with AutoSize=true.
By stepping through Vcl.Controls.pas, I see that my Label scales correctly at first , however when the next control (a radio group, it happens to be) is processed, the AlignControls is triggered, which changes my Label's Top.
The AlignControls function apparently can't handle the TLabel with the parameters I just described when called part-way through a rescaling operation.
I haven't firmly nailed down why, but I think it is because the parent Form or Frame has not yet been scaled (the ScaleControls function scales all the children before scaling the self), so it uses the form's old Height to calculate the actual Top that results from doing alignment to the bottom.
This effect is not triggered when loading the Form the first time, because the scaling code checks for csLoading component state and disables a whole lot of reactionary effects, including the call to AlignControls.
I haven't figured out why the bug is only triggered when ParentFont=false.
My current workaround is to include a line in the FormResize handler that manually realigns the Labels in question with another label that has ParentFont=true (and thus doesn't suffer from the bug).

How to change position of slider without calling change/slide methods?

I have a slider. When the user slides it, it adjusts the gamma of an image. Here is the code, very straightforward, works perfectly.
$('#gammaSlider').slider({
max: 125,
min: -125,
value: 0,
slide: function () {
//stuff to adjust gamma of image
},
change: function () {
//stuff to adjust gamma of image
}
});
However, when the user loads a different image, I want to programmatically set the slider to the value it should be at for the new image (a.k.a. allow flipping back and forth between multiple pages with separate gamma settings). To be clear, the newly loaded image's gamma is already at whatever value it was last set to. I am only seeking to adjust the UI to match the new image's value. For instance, if I increase page 2's gamma, then flip to page 1, I need to move the slider back to default from its increased position, and I need to do it without the code thinking I'm trying to decrease the gamma.
When I do this using the following, there's a problem:
$('#gammaSlider').slider('value', gamma);
The problem is that this is triggering the slide and change calls that I set up for the slider in the original declaration above, causing it to try to reload the image redundantly with new gamma values. Is there a way to change the slider programmatically WITHOUT triggering those calls?
You can use the fact that you can differentiate between a user change and a programmatic change via event.originalEvent. For example, you can have code that gets executed when the user makes a change, and different code that gets executed when you make a programmatic change like changing the value. Since changing the value will trigger the slider's change event, you can put your gamma change code within the block that only is triggered on a user's change, not a programmatic change:
change: function (event) {
if (event.originalEvent) {
//stuff to adjust gamma of image ONLY WHEN USER CHANGES THE SLIDER
console.log('user change');
}
}
You can see in this jsFiddle example that the slider's value is changed to 50, yet no log message is generated unless the user moves the slider. If you comment out the if condition you'll see the log message gets generated not only after the user changes the slider's value, but when you make a change to the value programmatically.
Maybe you can call the slider method passing a new configuration, which probably would be exactly the same object you are passing as parameter, but with the "value" field changed.
I have done a test in one of my old projects and it worked for me.

Play movie clip, have it wait until end of main movie then restart

I have a flash banner that includes a movie clip of the logo being animated. I want the logo animation to only run at the beginning of the main "movie". Currently I have to find the length of the entire movie (for ex. 500 frames) then put a key frame in at the 500th frame of the logo movie clip. I know there has to be a correct way to do this...Do I add a frame name at the end of the main timeline and somehow in AS in the logo movie clip say "when you reach X goToAndPlay(1);"?
Well, you can't simply do a "when you do this, do that".
There are two ways that come to my mind right now. First the (more) proper one is to add an dispatchEvent( new Event(__EVENT_TYPE__)); to the frame you want to stop on and than add a listener to the movieclip like:
mc1.addEventListener(Event.__EVENT_TYPE__, stopPlayback);
function stopPlayback( e:Event ):void{
mc1.stop();
mc1.removeEventListener(Event.__EVENT_TYPE__, stopPlayback);
}
so that when the event is dispatched you will stop playback. You can use for example an Event.COMPLETE or maybe create a custom event.
The second way is to add a Event.ENTER_FRAME event listener than check if we are back to the first frame and if we have looped go back to the last one and stop, remove the event listener and done.
Also we need to store somewhere the last frame we were on so that we know to witch we need to get back.
mc1.addEventListener(Event.ENTER_FRAME, onEF);
var lastFrame:int = 0;
function onEF( e:Event ):void{
if(mc1.currentFrame == 1){
mc1.removeEventListener(Event.ENTER_FRAME, onEF);
mc1.gotoAndStop(lastFrame);
}
lastFrame = mc1.currentFrame;
}
use the second one only if you cant add a event dispatch to the movie clip (or a simple stop() call ;) )
Hope it helps
Cheers.

Resources