diff --git a/.gitignore b/.gitignore index 88146e9..0531b23 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,8 @@ /src/.flashProjectProperties /src/common/skse.as -/src/common/skyui \ No newline at end of file +/src/common/skyui + +# wip, random tests or notes that I don't want to version control +__* + diff --git a/src/CLIK/Mouse.as b/src/CLIK/Mouse.as index 0f6cf23..6750ede 100644 --- a/src/CLIK/Mouse.as +++ b/src/CLIK/Mouse.as @@ -3,6 +3,10 @@ // Mouse object //**************************************************************************** +// See: +// Scaleform AS2 Extensions Reference.pdf +// http://gameware.autodesk.com/documents/gfx_4.0_as2_extensions.pdf + intrinsic class Mouse { static function addListener(listener:Object):Void; @@ -13,4 +17,12 @@ intrinsic class Mouse // scaleform extensions // static function getTopMostEntity(obj1:Object,obj2:Number,obj3:Boolean):Object; static function getTopMostEntity():Object; -} \ No newline at end of file + + /** + * This method returns coordinates of the corresponding mouse cursor, in _root + * coordinate space. The returned value is an instance of flash.geom.Point. + * + * Scaleform version: 2.2 + */ + static function getPosition(mouseIndex:Number):flash.geom.Point; +} diff --git a/src/common/Shared/BSScrollingList.as b/src/common/Shared/BSScrollingList.as index b2ae484..a67615f 100644 --- a/src/common/Shared/BSScrollingList.as +++ b/src/common/Shared/BSScrollingList.as @@ -3,6 +3,50 @@ import gfx.ui.InputDetails; import gfx.ui.NavigationCode; import gfx.events.EventDispatcher; +/* + Method summary: + + function BSScrollingList() + function ClearList(): Void + function GetClipByIndex(aiIndex: Number): MovieClip + function handleInput(details: InputDetails, pathToFocus: Array): Boolean + function set selectedIndex(aiNewIndex: Number): Void + function set listAnimating(abFlag: Boolean): Void + function doSetSelectedIndex(aiNewIndex:Number, aiKeyboardOrMouse: Number): Void + function set scrollPosition(aiNewPosition: Number): Void + function updateScrollPosition(aiPosition: Number): Void + function UpdateList(): Void + function InvalidateData(): Void + function SetScrollbarVisibility(): Void + function CalculateMaxScrollPosition(): Void + function GetEntryHeight(aiEntryIndex: Number): Number + function moveSelectionUp(): Void + function moveSelectionDown(): Void + + function onLoad(): Void + function onMouseWheel(delta: Number): Void + function onItemPress(aiKeyboardOrMouse: Number): Void + function onItemPressAux(aiKeyboardOrMouse: Number, aiButtonIndex: Number) + function onScroll(event: Object): Void + + function SetEntry(aEntryClip: MovieClip, aEntryObject: Object): Void + function SetEntryText(aEntryClip: MovieClip, aEntryObject: Object): Void + + Getters/Setters: + + function get selectedIndex(): Number + function get listAnimating(): Boolean + function get selectedEntry(): Object + function get scrollPosition(): Number + function get maxScrollPosition(): Number + function get entryList(): Array + function get disableSelection(): Boolean + function get disableInput(): Boolean + function get maxEntries(): Number + function get textOption(): Number + + */ + class Shared.BSScrollingList extends MovieClip { static var TEXT_OPTION_NONE: Number = 0; @@ -34,6 +78,7 @@ class Shared.BSScrollingList extends MovieClip var iScrollPosition: Number; var iScrollbarDrawTimerID: Number; var iSelectedIndex: Number; + var iHighlightedIndex: Number; // new var iTextOption: Number; var itemIndex: Number; @@ -48,6 +93,7 @@ class Shared.BSScrollingList extends MovieClip Mouse.addListener(this); iSelectedIndex = -1; + iHighlightedIndex = -1; iScrollPosition = 0; iMaxScrollPosition = 0; iListItemsShown = 0; @@ -58,16 +104,19 @@ class Shared.BSScrollingList extends MovieClip for (var item: MovieClip = GetClipByIndex(iMaxItemsShown); item != undefined; item = GetClipByIndex(++iMaxItemsShown)) { item.clipIndex = iMaxItemsShown; + item.onRollOver = function () { if (!_parent.listAnimating && !_parent.bDisableInput && itemIndex != undefined) { - _parent.doSetSelectedIndex(itemIndex, 0); +//GlobalFunc.getInstance().Deebug("onRollOver() doSetSelectedIndex " + itemIndex); + _parent.doSetSelectedIndex(itemIndex, 0, true); _parent.bMouseDrivenNav = true; } }; item.onPress = function (aiMouseIndex, aiKeyboardOrMouse) { if (itemIndex != undefined) { +//GlobalFunc.getInstance().Deebug("item::onPress() " + aiKeyboardOrMouse); _parent.onItemPress(aiKeyboardOrMouse); if (!_parent.bDisableInput && onMousePress != undefined) onMousePress(); @@ -101,6 +150,7 @@ class Shared.BSScrollingList extends MovieClip function handleInput(details: InputDetails, pathToFocus: Array): Boolean { +//GlobalFunc.getInstance().Deebug("handleInput() BSScrollingList"); var bHandledInput: Boolean = false; if (!bDisableInput) { var item: MovieClip = GetClipByIndex(selectedIndex - scrollPosition); @@ -156,6 +206,50 @@ class Shared.BSScrollingList extends MovieClip bListAnimating = abFlag; } + //fabd++ The function can now set mouse highlight (visual) separately from the selected state + function doSetSelectedIndex(aiNewIndex:Number, aiKeyboardOrMouse: Number, abMouseFocus: Boolean): Void + { + // current focus is selectedindex, or mouse highlighted index (decoupled from selection) + var iCurHighlightIndex = iHighlightedIndex; // abMouseFocus ? iHighlightedIndex : iSelectedIndex; + + if (!bDisableSelection) { + + // change selectedIndex, unless explicitly doing the mouse highlighting + if (abMouseFocus !== true) { + iSelectedIndex = aiNewIndex; + } + + if (aiNewIndex != iCurHighlightIndex) { + var iCurrentIndex: Number = iHighlightedIndex; + + iHighlightedIndex = aiNewIndex; +//GlobalFunc.getInstance().Deebug("iHighlightedIndex = " + iHighlightedIndex); + + if (iCurrentIndex != -1) + SetEntry(GetClipByIndex(EntriesA[iCurrentIndex].clipIndex), EntriesA[iCurrentIndex]); + + if (iHighlightedIndex != -1) { + if (iPlatform != 0) { + if (iHighlightedIndex < iScrollPosition) + scrollPosition = iHighlightedIndex; + else if (iHighlightedIndex >= iScrollPosition + iListItemsShown) + scrollPosition = Math.min(iHighlightedIndex - iListItemsShown + 1, iMaxScrollPosition); + else + SetEntry(GetClipByIndex(EntriesA[iHighlightedIndex].clipIndex),EntriesA[iHighlightedIndex]); + } else { + SetEntry(GetClipByIndex(EntriesA[iHighlightedIndex].clipIndex),EntriesA[iHighlightedIndex]); + } + } + + // note: this could have unwanted effects here, since highlighted is not always *selected* + // note: OR... dispatch only when selectedIndex changes... usually would want highlight change + dispatchEvent({type:"selectionChange", index:iHighlightedIndex, keyboardOrMouse:aiKeyboardOrMouse}); + } + } + } + + //fabd-- the old code for reference + /* function doSetSelectedIndex(aiNewIndex:Number, aiKeyboardOrMouse: Number): Void { if (!bDisableSelection && aiNewIndex != iSelectedIndex) { @@ -180,6 +274,7 @@ class Shared.BSScrollingList extends MovieClip dispatchEvent({type:"selectionChange", index:iSelectedIndex, keyboardOrMouse:aiKeyboardOrMouse}); } } + */ function get scrollPosition(): Number { @@ -266,24 +361,24 @@ class Shared.BSScrollingList extends MovieClip { var iFirstItemy: Number = GetClipByIndex(0)._y; var iItemHeightSum: Number = 0; - var iLastItemShownIndex: Number = 0; - while (iLastItemShownIndex < iScrollPosition) { - EntriesA[iLastItemShownIndex].clipIndex = undefined; - ++iLastItemShownIndex; + var i: Number = 0; + while (i < iScrollPosition) { + EntriesA[i].clipIndex = undefined; + ++i; } iListItemsShown = 0; - iLastItemShownIndex = iScrollPosition; - while (iLastItemShownIndex < EntriesA.length && iListItemsShown < iMaxItemsShown && iItemHeightSum <= fListHeight) { + i = iScrollPosition; + while (i < EntriesA.length && iListItemsShown < iMaxItemsShown && iItemHeightSum <= fListHeight) { var item: MovieClip = GetClipByIndex(iListItemsShown); - SetEntry(item, EntriesA[iLastItemShownIndex]); - EntriesA[iLastItemShownIndex].clipIndex = iListItemsShown; - item.itemIndex = iLastItemShownIndex; + SetEntry(item, EntriesA[i]); + EntriesA[i].clipIndex = iListItemsShown; + item.itemIndex = i; item._y = iFirstItemy + iItemHeightSum; item._visible = true; iItemHeightSum += item._height; if (iItemHeightSum <= fListHeight && iListItemsShown < iMaxItemsShown) ++iListItemsShown; - ++iLastItemShownIndex; + ++i; } var iLastItemIndex: Number = iListItemsShown; while (iLastItemIndex < iMaxItemsShown) { @@ -365,9 +460,16 @@ class Shared.BSScrollingList extends MovieClip scrollPosition = scrollPosition + 1; } + /** + * MovieClip onPress() aiKeyboardOrMouse == 0 + * + * If keyboard (handleInput), aiKeyboardOrMouse is undefined. + * + */ function onItemPress(aiKeyboardOrMouse: Number): Void { if (!bDisableInput && !bDisableSelection && iSelectedIndex != -1) { +//GlobalFunc.getInstance().Deebug("onItemPress() aiKeyboardOrMouse = " + aiKeyboardOrMouse); dispatchEvent({type: "itemPress", index: iSelectedIndex, entry: EntriesA[iSelectedIndex], keyboardOrMouse: aiKeyboardOrMouse}); return; } @@ -380,10 +482,13 @@ class Shared.BSScrollingList extends MovieClip dispatchEvent({type: "itemPressAux", index: iSelectedIndex, entry: EntriesA[iSelectedIndex], keyboardOrMouse: aiKeyboardOrMouse}); } + // New: aSelectedEntry is based on highlighted index, which is not always selected index function SetEntry(aEntryClip: MovieClip, aEntryObject: Object): Void { + var aSelectedEntry: Object = EntriesA[iHighlightedIndex]; + if (aEntryClip != undefined) { - if (aEntryObject == selectedEntry) + if (aEntryObject == aSelectedEntry) aEntryClip.gotoAndStop("Selected"); else aEntryClip.gotoAndStop("Normal"); diff --git a/src/common/Shared/CenteredScrollingList.as b/src/common/Shared/CenteredScrollingList.as index 755288c..93c85ae 100644 --- a/src/common/Shared/CenteredScrollingList.as +++ b/src/common/Shared/CenteredScrollingList.as @@ -206,6 +206,9 @@ class Shared.CenteredScrollingList extends Shared.BSScrollingList if (itemIndex != undefined) { iSelectedIndex = itemIndex; + iHighlightedIndex = itemIndex; //fabd++ + bRecenterSelection = true; //fabd++ + if (iScrollPosition > 0) --iScrollPosition; bMouseDrivenNav = false; @@ -224,6 +227,9 @@ class Shared.CenteredScrollingList extends Shared.BSScrollingList } if (itemIndex != undefined) { iSelectedIndex = itemIndex; + iHighlightedIndex = itemIndex; //fabd++ + bRecenterSelection = true; //fabd++ + if (iScrollPosition < iMaxScrollPosition) ++iScrollPosition; bMouseDrivenNav = false; @@ -273,6 +279,8 @@ class Shared.CenteredScrollingList extends Shared.BSScrollingList function SetEntry(aEntryClip: MovieClip, aEntryObject: Object): Void { + var aSelectedEntry: Object = EntriesA[iHighlightedIndex]; + if (aEntryClip != undefined) { if (IsDivider(aEntryObject) == true) aEntryClip.gotoAndStop("Divider"); @@ -280,7 +288,7 @@ class Shared.CenteredScrollingList extends Shared.BSScrollingList aEntryClip.gotoAndStop("Normal"); if (iPlatform == 0) { - aEntryClip._alpha = aEntryObject == selectedEntry ? 100 : 60; + aEntryClip._alpha = aEntryObject == aSelectedEntry ? 100 : 60; } else { var iAlphaMulti: Number = 4; if (aEntryClip.clipIndex < iNumTopHalfEntries) diff --git a/src/common/Shared/GlobalFunc.as b/src/common/Shared/GlobalFunc.as index a9f6b94..3217312 100644 --- a/src/common/Shared/GlobalFunc.as +++ b/src/common/Shared/GlobalFunc.as @@ -3,10 +3,81 @@ class Shared.GlobalFunc static var RegisteredTextFields: Object = new Object(); static var RegisteredMovieClips: Object = new Object(); - function GlobalFunc() + // mini console log for debugging + private var debugWindow:MovieClip = null; + private var debugBg:MovieClip = null; + private var debugTxt:TextField = null; + + private var DEBUGLOG_HEIGHT:Number = 100; + + // singleton instance + private static var inst:GlobalFunc = null; + + public function GlobalFunc() + { + if (debugWindow != null) { + throw new Error("Woopsie doo."); + } + CreateDebugLog(); + } + + /** + * Dynamically create a mini console for debugging. + * + */ + public static function getInstance(): GlobalFunc + { + if (inst == null) { + inst = new GlobalFunc(); + } + return inst; + } + + private function CreateDebugLog(): Void { + debugWindow = _root.createEmptyMovieClip("debugWindow", _root.getNextHighestDepth()); + debugBg = debugWindow.createEmptyMovieClip("debugBg", debugWindow.getNextHighestDepth()); + + debugBg.beginFill(0x000000); + debugBg.moveTo(0, 0); + debugBg.lineTo(Stage.width, 0); + debugBg.lineTo(Stage.width, DEBUGLOG_HEIGHT); + debugBg.lineTo(0, DEBUGLOG_HEIGHT); + debugBg.lineTo(0, 0); + debugBg.endFill(); + debugBg._alpha = 50; + + debugTxt = debugWindow.createTextField("debugTxt", debugWindow.getNextHighestDepth(), 10, 10, (Stage.width/2) - 20, DEBUGLOG_HEIGHT-20); + debugTxt.embedFonts = true; + debugTxt.multiline = true; + debugTxt.wordWrap = false; + + debugWindow._x = 0; + debugWindow._y = 0; + + var format:TextFormat = new TextFormat("$ConsoleFont", 14, 0xCCCCCC); + debugTxt.setNewTextFormat(format); } + // Log debug text + public function Deebug(aText: String, ret:Boolean): Void + { + if (debugTxt.text == "") { + ret = false; + } + + // newline by default + if (ret !== false) { + ret = true; + } + + debugTxt.text += (ret ? "\r" : "") + aText; + + if (debugTxt.textHeight > debugTxt._height) { + debugTxt.scroll = debugTxt.textHeight - debugTxt._height; + } + } + static function Lerp(aTargetMin: Number, aTargetMax: Number, aSourceMin: Number, aSourceMax: Number, aSource: Number, abClamp: Boolean): Number { var normVal: Number = aTargetMin + (aSource - aSourceMin) / (aSourceMax - aSourceMin) * (aTargetMax - aTargetMin); diff --git a/src/dialoguemenu - fab cs4.fla b/src/dialoguemenu - fab cs4.fla new file mode 100644 index 0000000..0a9e1ad Binary files /dev/null and b/src/dialoguemenu - fab cs4.fla differ diff --git a/src/dialoguemenu/DialogueCenteredList.as b/src/dialoguemenu/DialogueCenteredList.as index 982a3bb..e2fee72 100644 --- a/src/dialoguemenu/DialogueCenteredList.as +++ b/src/dialoguemenu/DialogueCenteredList.as @@ -1,4 +1,6 @@ -class DialogueCenteredList extends Shared.CenteredScrollingList +import Shared.GlobalFunc; //fabd++ + +class DialogueCenteredList extends Shared.CenteredScrollingList { var EntriesA: Array; @@ -14,6 +16,7 @@ var iScrollPosition: Number; var iSelectedIndex: Number; + function DialogueCenteredList() { super(); @@ -35,6 +38,8 @@ var centerIndex: Number = iScrollPosition - iNumTopHalfEntries < 0 ? 0 : iScrollPosition - iNumTopHalfEntries; +//GlobalFunc.getInstance().Deebug("UpdateList() ci " + centerIndex + " iscroll " + iScrollPosition + " sel " + iSelectedIndex); + iListItemsShown = 0; for (var i: Number = 0; i < iNumTopHalfEntries; i++) { @@ -57,6 +62,7 @@ if (bRecenterSelection || iPlatform != 0) { iSelectedIndex = centerIndex; + iHighlightedIndex = centerIndex; //fabd++ } for (var i = centerIndex; i < EntriesA.length && iListItemsShown < iMaxItemsShown && listCumulativeHeight <= fListHeight; i++) { @@ -76,16 +82,13 @@ GetClipByIndex(i)._visible = false; GetClipByIndex(i).itemIndex = undefined; } - - - if (!bRecenterSelection) { - for (var target: Object = Mouse.getTopMostEntity(); target != undefined; target = target._parent) { - if (target._parent == this && target._visible && target.itemIndex != undefined) { - doSetSelectedIndex(target.itemIndex,0); - } - } - } - + + //fabd-- we no longer do this since we always scroll around the center item + /*if (!bRecenterSelection) { + // moved to function below + SetSelectedIndexByMouse(true); + }*/ + bRecenterSelection = false; RepositionEntries(); var imaxItemsBelowShown: Number = 3; @@ -93,6 +96,17 @@ _parent.ScrollIndicators.Down._visible = EntriesA.length - scrollPosition - 1 > imaxItemsBelowShown || listCumulativeHeight > fListHeight; } + // find the clicked dialog item, and make it the selected index + function SetSelectedIndexByMouse(abMouseHighlight: Boolean) + { + for (var target: Object = Mouse.getTopMostEntity(); target != undefined; target = target._parent) { + if (target._parent == this && target._visible && target.itemIndex != undefined) { +//GlobalFunc.getInstance().Deebug("SetSelectedIndexByMouse() " + target.itemIndex); + doSetSelectedIndex(target.itemIndex, 0, abMouseHighlight); + } + } + } + function RepositionEntries() { var item_yOffset = GetClipByIndex(iNumTopHalfEntries)._y + GetClipByIndex(iNumTopHalfEntries)._height / 2; @@ -111,17 +125,32 @@ return; } - iSelectedIndex = -1; - bRecenterSelection = true; + // iSelectedIndex = -1; + // bRecenterSelection = true; + /*fabd-- disabled because we always want the selection to be the center for (var target: Object = Mouse.getTopMostEntity(); target && target != undefined; target = target._parent) { if (target == this) { bRecenterSelection = false; } - } + }*/ var listItem: MovieClip - + + //fabd++ List_mc (this) => TopicListHolder => DialogueMenu_mc + var dialogueMenuObj: DialogueMenu = DialogueMenu(_parent._parent); +//GlobalFunc.getInstance().Deebug("onMouseWheel() menuState == " + dialogueMenuObj.menuState); + if (dialogueMenuObj.menuState == DialogueMenu.TOPIC_LIST_SHOWN) + { + if (delta < 0) { + moveSelectionDown(); + } else { + moveSelectionUp(); + } + } + + // Vanilla scroll wheel handling for reference + /* if (delta < 0) { listItem = GetClipByIndex(iNumTopHalfEntries + 1); if (listItem._visible == true) { @@ -132,18 +161,22 @@ if (listItem._visible == true) { scrollPosition = scrollPosition - 1; } - } + }*/ + return; } function SetSelectedTopic(aiTopicIndex: Number): Void { +//GlobalFunc.getInstance().Deebug("SetSelectedTopic() " + aiTopicIndex); iSelectedIndex = 0; iScrollPosition = 0; for (var i: Number = 0; i < EntriesA.length; i++) { if (EntriesA[i].topicIndex == aiTopicIndex) { iScrollPosition = i; + iSelectedIndex = i; //fabd++ + iHighlightedIndex = i; //fabd++ } } } diff --git a/src/dialoguemenu/DialogueMenu.as b/src/dialoguemenu/DialogueMenu.as index 58fec8d..7be6d34 100644 --- a/src/dialoguemenu/DialogueMenu.as +++ b/src/dialoguemenu/DialogueMenu.as @@ -67,12 +67,14 @@ class DialogueMenu extends MovieClip TopicListHolder.PanelCopy_mc._visible = false; FocusHandler.instance.setFocus(TopicList, 0); - + SubtitleText.verticalAutoSize = "top"; SubtitleText.SetText(" "); SpeakerName.verticalAutoSize = "top"; SpeakerName.SetText(" "); + +// GlobalFunc.getInstance().Deebug("DialogueMenu::InitExtensions() done."); } function AdjustForPALSD(): Void @@ -93,6 +95,7 @@ class DialogueMenu extends MovieClip function handleInput(details: InputDetails, pathToFocus: Array): Boolean { +//GlobalFunc.getInstance().Deebug("handleInput() DialogueMenu"); if (bFadedIn && GlobalFunc.IsKeyPressed(details)) { if (details.navEquivalent == NavigationCode.TAB) { onCancelPress(); @@ -179,11 +182,17 @@ class DialogueMenu extends MovieClip TopicListHolder.PanelCopy_mc._visible = abCopyVisible; } + /** + * onPress() from MovieClip has event.keyboardOrMouse == 0. + * + * If mouse or keyboard (handleInput), keyboardOrMouse is undefined. + * + */ function onItemSelect(event: Object): Void { if (bAllowProgress && event.keyboardOrMouse != 0) { if (eMenuState == DialogueMenu.TOPIC_LIST_SHOWN) { - onSelectionClick(); + onSelectionClick(event && event.mouseClick); } else if (eMenuState == DialogueMenu.TOPIC_CLICKED || eMenuState == DialogueMenu.SHOW_GREETING) { SkipText(); } @@ -199,11 +208,16 @@ class DialogueMenu extends MovieClip } } + /** + * Responds to clicks at the DialogueMenu MovieClip level (whole screen). + * + * Does not result in selection because aiKeyboardOrMouse is undefined. + */ function onMouseDown(): Void { ++DialogueMenu.iMouseDownExecutionCount; if (DialogueMenu.iMouseDownExecutionCount % 2 != 0) { - onItemSelect(); + onItemSelect({mouseClick: true}); } } @@ -240,8 +254,14 @@ class DialogueMenu extends MovieClip } } - function onSelectionClick(): Void + function onSelectionClick(abMouseClick: Boolean): Void { + // If it's a mouse click, set the selected index now + if (abMouseClick) { + TopicList.SetSelectedIndexByMouse(false); +// GlobalFunc.getInstance().Deebug("now selectedIndex = " + TopicList.selectedIndex); + } + if (eMenuState == DialogueMenu.TOPIC_LIST_SHOWN) { eMenuState = DialogueMenu.TOPIC_CLICKED; }