// ==================================================================== // (C) 2002, Epic Games // ==================================================================== class GUIVertImageList extends GUIVertList Native; cpptext { void PreDraw(UCanvas* Canvas); void Draw(UCanvas* Canvas); void DrawItem( UCanvas* Canvas, INT Item, FLOAT X, FLOAT Y, FLOAT XL, FLOAT YL, UBOOL bSelected, UBOOL bPending ); } var() eCellStyle CellStyle; var() float ImageScale; // Scale value for the images var() int NoVisibleRows; // How many rows of visible images are there var() int NoVisibleCols; // How many cols of visible images are there var() int HorzBorder, VertBorder; // How much white space var() editconstarray editconst array Elements; var() editconstarray editconst array SelectedElements; var() material LockedMat; event int CalculateIndex( optional bool bRequireValidIndex ) { local int i; local int HitCol, HitRow; HitCol = (Controller.MouseX - ClientBounds[0]) / ItemWidth; HitRow = (Controller.MouseY - ClientBounds[1]) / ItemHeight; i = Top + HitCol + (HitRow * NoVisibleCols); if ( (i < 0 || i >= ItemCount) && bRequireValidIndex ) return -1; return i; } function bool InternalOnClick(GUIComponent Sender) { local int NewIndex; if ( !IsInClientBounds() || ItemsPerPage==0 ) return false; NewIndex = CalculateIndex(); if ( !IsValidIndex(NewIndex) ) return false; SetIndex(NewIndex); return true; } function int SetIndex(int NewIndex) { if (Elements[NewIndex].Locked==1) return Index; return super.SetIndex(NewIndex); } function bool Up() { local int TargetIndex; if ( Index - NoVisibleCols < 0 ) return true; TargetIndex = Index-NoVisibleCols; if ( Elements[TargetIndex].Locked==1 ) { TargetIndex = TargetIndex-NoVisibleCols; if ( TargetIndex<0 || Elements[TargetIndex].Locked==1 ) return true; } SetIndex(TargetIndex); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); return true; } function bool Down() { local int TargetIndex; if ( Index + NoVisibleCols >= ItemCount ) return true; TargetIndex = Index + NoVisibleCols; if ( Elements[TargetIndex].Locked==1 ) { TargetIndex = TargetIndex + NoVisibleCols; if ( TargetIndex >= ItemCount || Elements[TargetIndex].Locked==1 ) return true; } SetIndex(TargetIndex); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); return true; } function bool MoveRight() { local int TargetIndex; TargetIndex = ( Index + 1 ); if ( TargetIndex % NoVisibleCols == 0 ) return true; if (Elements[TargetIndex].Locked==1) { TargetIndex++; if ( (TargetIndex % NoVisibleCols == 0 ) || (Elements[TargetIndex].Locked==1) ) return true; } if ( TargetIndex < ItemCount ) SetIndex(TargetIndex); return true; } function bool MoveLeft() { local int TargetIndex; if ( Index % NoVisibleCols == 0 ) return true; TargetIndex = Index - 1; if (Elements[TargetIndex].Locked==1) { TargetIndex--; if (TargetIndex<0 || TargetIndex%NoVisibleCols==NoVisibleCols-1 || Elements[TargetIndex].Locked==1) return true; } if ( Index > 0 ) SetIndex(TargetIndex); return true; } function Home() { local int i; if ( ItemCount < 2 ) return; for (i=0;i0;i--) if (Elements[i].Locked!=1) { SetIndex( i ); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); return; } } function PgUp() { local int newtop; if (Top > 0) { NewTop = max(0,Top-NoVisibleRows); SetTopItem(NewTop); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); } return; } function PgDn() { local int newtop; if ( Top < (ItemCount / NoVisibleCols) - NoVisibleRows) { NewTop = Max(0, Top+NoVisibleRows); SetTopItem(NewTop); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); } return; } function MakeVisible(float Perc) { local float MaxTop, ModResult; local int NewTop, Change; MaxTop = ItemCount - ItemsPerPage; ModResult = MaxTop % NoVisibleCols; if ( ModResult > 0 ) MaxTop = (MaxTop - ModResult) + NoVisibleCols; // NewItem is number of hidden items * Perc we want to show // Round off result before adjusting top to prevent constant flipping back and forth between two items // or if we're attempting to view the last row NewTop = Round(MaxTop * Perc); Change = Abs(Top - NewTop); if ( Change < NoVisibleCols && Perc < 1.0) return; SetTopItem(NewTop); } function SetTopItem(int Item) { local int ModResult; // clamp new top to prevent displaying space below last items of list Item = Clamp(Item, 0, ItemCount - 1); // Adjust the result to fall on the first column - otherwise, elements might get shifted to a different column ModResult = Item % NoVisibleCols; if ( ModResult > 0 ) { // If we had leftover items, we'll need another row if ( Item > Top ) Item += NoVisibleCols; Item -= ModResult; } // But if we went too far (more than itemcount + numcolumns), then back it up while ( (Item + ItemsPerPage > ItemCount + NoVisibleCols) && Item >= 0) Item -= NoVisibleCols; Top = Max( 0, Item ); OnAdjustTop(Self); } function Add(Material Image, optional int Item, optional int Locked) { local int i; if ( Image == None && !bAllowEmptyItems ) return; i = Elements.Length; Elements.Length = i + 1; Elements[i].Image = Image; Elements[i].Item = Item; Elements[i].Locked = Locked; ItemCount = Elements.Length; if (ItemCount == 1 && bInitializeList) SetIndex(0); else CheckLinkedObjects(Self); if (MyScrollBar != None) MyScrollBar.AlignThumb(); } function AddImage( ImageListElem NewElem, optional int Locked) { Add(NewElem.Image, NewElem.Item, Locked); } function Replace(int i, Material NewImage, optional int NewItem, optional int Locked) { if ( !IsValidIndex(i) ) Add(NewImage, NewItem); else { if ( !bAllowEmptyItems && NewImage == None ) return; Elements[i].Item = NewItem; Elements[i].Image = NewImage; Elements[i].Locked = Locked; SetIndex(Index); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); } } function Insert(int i, Material NewImage, optional int NewItem, optional int Locked) { if ( !IsValidIndex(i) ) Add(NewImage,NewItem); else { if ( !bAllowEmptyItems && NewImage == None ) return; Elements.Insert(i,1); Elements[i].Item=NewItem; Elements[i].Image = NewImage; Elements[i].Locked = Locked; ItemCount = Elements.Length; SetIndex(Index); if (MyScrollBar != None) MyScrollBar.AlignThumb(); } } function InsertElement( int i, ImageListElem NewElem, optional int Locked ) { Insert( i, NewElem.Image, NewElem.Item, Locked ); } event Swap(int IndexA, int IndexB) { local ImageListElem elem; if ( IsValidIndex(IndexA) && IsValidIndex(IndexB) ) { elem = Elements[IndexA]; Elements[IndexA] = Elements[IndexB]; Elements[IndexB] = elem; } } function LoadFrom(GUIVertImageList Source, optional bool bClearFirst) { local int i, item; local Material mat; local int l; if (bClearfirst) Clear(); for ( i = 0; i < Source.ItemCount; i++ ) { Source.GetAtIndex(i,mat,item,l); Add(mat,item,l); } } function int Remove(int i, optional int Count) { Count = Max( Count, 1 ); if (!IsValidIndex(i)) return Index; Elements.Remove(i, Min(Count, Elements.Length - i)); ItemCount = Elements.Length; // In case we now have an invalid index SetIndex(Index); if (MyScrollBar != None) MyScrollBar.AlignThumb(); return Index; } function int RemoveSilent(int i, optional int Count) { bNotify = False; i = Remove(i, Count); bNotify = True; return i; } function int RemoveElement(ImageListElem Elem, optional int Count) { local int i; Count = Max( Count, 1 ); for ( i = 0; i < Elements.Length; i++ ) { if ( Elements[i] == Elem ) { Elements.Remove(i, Min(Count, Elements.Length - i)); break; } } ItemCount = Elements.Length; // In case we now have an invalid index SetIndex(Index); if ( MyScrollBar != None ) MyScrollBar.AlignThumb(); return Index; } function Clear() { if (ItemCount == 0) return; Elements.Remove(0,Elements.Length); Super.Clear(); } // ===================================================================================================================== // ===================================================================================================================== // Query Functions // ===================================================================================================================== // ===================================================================================================================== function Material Get(optional bool bGuarantee) { if ( !IsValid() ) { if (bGuarantee && ItemCount > 0) return Elements[0].Image; return None; } return Elements[Index].Image; } function int GetItem() { if ( !IsValid() ) return -1; return Elements[Index].Item; } // Arbitrary list Item function Material GetImageAtIndex(int i) { if (!IsValidIndex(i)) return None; return Elements[i].Image; } function string GetItemAtIndex(int i) { return string(GetItemIntAtIndex(i)); } function int GetItemIntAtIndex(int i) { if (!IsValidIndex(i)) return -1; return Elements[i].Item; } function GetAtIndex(int i, out Material Image, out int Item, out int Locked) { if (!IsValidIndex(i)) return; Image = Elements[i].Image; Item = Elements[i].Item; Locked = Elements[i].Locked; } function bool IndexLocked(int i) { return Elements[i].Locked==1; } function bool IsLocked() { return Elements[Index].Locked==1; } function ClearPendingElements() { Super.ClearPendingElements(); SelectedElements.Remove(0, SelectedElements.Length); } function array GetPendingElements(optional bool bGuarantee) { local int i; if ( (DropState == DRP_Source && Controller.DropSource == Self) || bGuarantee ) { if ( SelectedElements.Length == 0 ) { for (i = 0; i < SelectedItems.Length; i++) if (IsValidIndex(SelectedItems[i])) SelectedElements[SelectedElements.Length] = Elements[SelectedItems[i]]; if ( SelectedElements.Length == 0 && IsValid() ) { SelectedElements.Length = SelectedElements.Length + 1; GetAtIndex(Index, SelectedElements[0].Image, SelectedElements[0].Item, SelectedElements[0].Locked); } } return SelectedElements; } } //############################################################################## // // Assignment functions // function SetImageAtIndex(int i, Material NewImage) { if ( !IsValidIndex(i) ) return; Elements[i].Image = NewImage; } function SetItemAtIndex(int i, int NewItem) { if (!IsValidIndex(i)) return; Elements[i].Item = NewItem; } function RemoveImage( Material Image ) { local int i; i = FindImage(Image); if ( IsValidIndex(i) ) Remove(i); } function RemoveItem(int Item) { local int i; for ( i = Elements.Length -1; i >= 0; i-- ) if ( Elements[i].Item == Item ) Remove(i); ItemCount = Elements.Length; SetIndex(Index); if (MyScrollBar != None) MyScrollBar.AlignThumb(); } //############################################################################## // // Search functions // function int FindImage( Material Image ) { local int i; if ( Image == None && !bAllowEmptyItems ) return -1; for ( i = 0; i < Elements.Length; i++ ) if ( Elements[i].Image == Image ) return i; return -1; } function int FindItem( int Item ) { local int i; for ( i = 0; i < Elements.Length; i++ ) if ( Elements[i].Item == Item ) return i; return -1; } // Called on the drop source when when an Item has been dropped. bAccepted tells it whether // the operation was successful or not. function InternalOnEndDrag(GUIComponent Accepting, bool bAccepted) { local int i; // log(Name@"InternalOnEndDrag Accepting:"$Accepting@"bAccepted:"$bAccepted); if (bAccepted && Accepting != None) { GetPendingElements(); if ( Accepting != Self ) { for ( i = 0; i < SelectedElements.Length; i++ ) RemoveElement(SelectedElements[i]); } bRepeatClick = False; } // Simulate repeat click if the operation was a failure to prevent InternalOnMouseRelease from clearing // the SelectedItems array // This way we don't lose the items we clicked on if (Accepting == None) bRepeatClick = True; SetOutlineAlpha(255); if ( bNotify ) CheckLinkedObjects(Self); } // Called on the drop target when the mouse is released - Sender is always DropTarget function bool InternalOnDragDrop(GUIComponent Sender) { local array NewItem; local int i; // log(Name@"InternalOnDragDrop Sender:"$ Sender); if (Controller.DropTarget == Self) { if (Controller.DropSource != None && GUIVertImageList(Controller.DropSource) != None) { NewItem = GUIVertImageList(Controller.DropSource).GetPendingElements(); // Special case for drag-n-drop between the same list. if ( Controller.DropSource == Self ) { for ( i = NewItem.Length - 1; i >= 0; i-- ) RemoveElement(NewItem[i]); } if ( !IsValidIndex(DropIndex) ) DropIndex = ItemCount; for (i = NewItem.Length - 1; i >= 0; i--) Insert(DropIndex, NewItem[i].Image, NewItem[i].Item); SetIndex(DropIndex); return true; } } return false; } defaultproperties { OnClick=InternalOnClick CellStyle=Cell_FixedSize ImageScale=1.0 StyleName="" HorzBorder=5 VertBorder=5 NoVisibleRows=4 NoVisibleCols=3 }