├── .github ├── Images │ ├── 1.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 4_1.png │ └── 5.png └── README.md ├── LICENSE.txt ├── LICENSE.txt.meta ├── Plugins.meta ├── Plugins ├── DynamicPanels.meta └── DynamicPanels │ ├── Cursors.meta │ ├── Cursors │ ├── CursorResizeHorizontal.psd │ ├── CursorResizeHorizontal.psd.meta │ ├── CursorResizeTopLeft.psd │ ├── CursorResizeTopLeft.psd.meta │ ├── CursorResizeTopRight.psd │ ├── CursorResizeTopRight.psd.meta │ ├── CursorResizeVertical.psd │ └── CursorResizeVertical.psd.meta │ ├── DemoScene.unity │ ├── DemoScene.unity.meta │ ├── DynamicPanels.Runtime.asmdef │ ├── DynamicPanels.Runtime.asmdef.meta │ ├── Editor.meta │ ├── Editor │ ├── DynamicPanels.Editor.asmdef │ ├── DynamicPanels.Editor.asmdef.meta │ ├── DynamicPanelsCanvasEditor.cs │ └── DynamicPanelsCanvasEditor.cs.meta │ ├── README.txt │ ├── README.txt.meta │ ├── Resources.meta │ ├── Resources │ ├── DynamicPanel.prefab │ ├── DynamicPanel.prefab.meta │ ├── DynamicPanelPreview.prefab │ ├── DynamicPanelPreview.prefab.meta │ ├── DynamicPanelTab.prefab │ └── DynamicPanelTab.prefab.meta │ ├── Scripts.meta │ ├── Scripts │ ├── Anchoring.meta │ ├── Anchoring │ │ ├── AnchorZoneBase.cs │ │ ├── AnchorZoneBase.cs.meta │ │ ├── CanvasAnchorZone.cs │ │ ├── CanvasAnchorZone.cs.meta │ │ ├── PanelAnchorZone.cs │ │ ├── PanelAnchorZone.cs.meta │ │ ├── PanelHeaderAnchorZone.cs │ │ └── PanelHeaderAnchorZone.cs.meta │ ├── DynamicPanelsCanvas.cs │ ├── DynamicPanelsCanvas.cs.meta │ ├── Grouping.meta │ ├── Grouping │ │ ├── IPanelGroupElement.cs │ │ ├── IPanelGroupElement.cs.meta │ │ ├── PanelGroup.cs │ │ ├── PanelGroup.cs.meta │ │ ├── UnanchoredPanelGroup.cs │ │ └── UnanchoredPanelGroup.cs.meta │ ├── Helpers.meta │ ├── Helpers │ │ ├── NonDrawingGraphic.cs │ │ ├── NonDrawingGraphic.cs.meta │ │ ├── PanelCursorHandler.cs │ │ ├── PanelCursorHandler.cs.meta │ │ ├── PanelHeader.cs │ │ ├── PanelHeader.cs.meta │ │ ├── PanelNotificationCenter.cs │ │ ├── PanelNotificationCenter.cs.meta │ │ ├── PanelResizeHelper.cs │ │ ├── PanelResizeHelper.cs.meta │ │ ├── PanelSerialization.cs │ │ ├── PanelSerialization.cs.meta │ │ ├── PanelTab.cs │ │ ├── PanelTab.cs.meta │ │ ├── PanelUtils.cs │ │ └── PanelUtils.cs.meta │ ├── Panel.cs │ ├── Panel.cs.meta │ ├── PanelManager.cs │ └── PanelManager.cs.meta │ ├── Sprites.meta │ └── Sprites │ ├── CloseButton.psd │ ├── CloseButton.psd.meta │ ├── PanelBackground.psd │ ├── PanelBackground.psd.meta │ ├── PanelTabBackground.psd │ └── PanelTabBackground.psd.meta ├── package.json └── package.json.meta /.github/Images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/.github/Images/1.png -------------------------------------------------------------------------------- /.github/Images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/.github/Images/2.png -------------------------------------------------------------------------------- /.github/Images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/.github/Images/3.png -------------------------------------------------------------------------------- /.github/Images/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/.github/Images/4.png -------------------------------------------------------------------------------- /.github/Images/4_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/.github/Images/4_1.png -------------------------------------------------------------------------------- /.github/Images/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/.github/Images/5.png -------------------------------------------------------------------------------- /.github/README.md: -------------------------------------------------------------------------------- 1 | # Dynamic Panels for Unity 3D 2 | 3 | ![screenshot](Images/1.png) 4 | ![screenshot2](Images/2.png) 5 | *(used external assets in screenshots: [In-game Debug Console](https://github.com/yasirkula/UnityIngameDebugConsole) and [Runtime Inspector & Hierarchy](https://github.com/yasirkula/UnityRuntimeInspector))* 6 | 7 | **Available on Asset Store:** https://assetstore.unity.com/packages/tools/gui/dynamic-panels-114126 8 | 9 | **Forum Thread:** https://forum.unity.com/threads/released-dynamic-panels-draggable-resizable-dockable-and-stackable-ui-panels.523106/ 10 | 11 | **Discord:** https://discord.gg/UJJt549AaV 12 | 13 | **WebGL Demo:** http://yasirkula.net/DynamicPanelsDemo/ 14 | 15 | **[GitHub Sponsors ☕](https://github.com/sponsors/yasirkula)** 16 | 17 | ## ABOUT 18 | 19 | This asset helps you create dynamic panels using Unity's UI system. These panels can be dragged around, resized, docked to canvas edges or to one another and stacked next to each other as separate tabs. 20 | 21 | ## FEATURES 22 | 23 | - Supports all canvas modes (Screen Space and World Space) 24 | - Supports multiple canvases (panels can be moved between canvases by dragging) 25 | - Has an extensive Scripting API to create/manipulate panels by code 26 | - Each panel costs 3 additional batches (this number can increase with each tab using a custom icon) 27 | 28 | ## INSTALLATION 29 | 30 | There are 5 ways to install this plugin: 31 | 32 | - import [DynamicPanels.unitypackage](https://github.com/yasirkula/UnityDynamicPanels/releases) via *Assets-Import Package* 33 | - clone/[download](https://github.com/yasirkula/UnityDynamicPanels/archive/master.zip) this repository and move the *Plugins* folder to your Unity project's *Assets* folder 34 | - import it from [Asset Store](https://assetstore.unity.com/packages/tools/gui/dynamic-panels-114126) 35 | - *(via Package Manager)* click the + button and install the package from the following git URL: 36 | - `https://github.com/yasirkula/UnityDynamicPanels.git` 37 | - *(via [OpenUPM](https://openupm.com))* after installing [openupm-cli](https://github.com/openupm/openupm-cli), run the following command: 38 | - `openupm add com.yasirkula.dynamicpanels` 39 | 40 | ## FAQ 41 | 42 | - **New Input System isn't supported on Unity 2019.2.5 or earlier** 43 | 44 | Add `ENABLE_INPUT_SYSTEM` compiler directive to **Player Settings/Scripting Define Symbols** (these symbols are platform specific, so if you change the active platform later, you'll have to add the compiler directive again). 45 | 46 | - **"Unity.InputSystem" assembly can't be resolved on Unity 2018.4 or earlier** 47 | 48 | Remove `Unity.InputSystem` assembly from **DynamicPanels.Runtime** Assembly Definition File's *Assembly Definition References* list. 49 | 50 | ## HOW TO 51 | 52 | Add **Dynamic Panels Canvas** component to the *RectTransform* inside which your panels will reside. This RectTransform doesn't have to be the Canvas object itself, it can be a child of the canvas and it can have a custom size. 53 | 54 | There are two ways to create panels: by using the GUI of Dynamic Panels Canvas or via Scripting API. There are also two types of panels: *free panels* that can be moved around and resized freely and *docked panels* that are moved by the layout system, depending on where it is docked to. A panel can have multiple tabs. 55 | 56 | ![dynamic_panels_canvas](Images/4.png) 57 | 58 | To add a new free panel using the Dynamic Panels Canvas component, simply click the **Add New** button under the *Free Panels* section. Then, click the + button to start adding tabs to that panel. Each tab has 4 properties: the content (*RectTransform*) that will be displayed while the tab is active, a label, an optional icon, and the minimum size of the content associated with the tab. To remove a free panel, select a tab inside the panel and click the **Remove Selected** button. 59 | 60 | You can create docked panels by using the buttons under the *Docked Panels* section. To create a panel that is docked to the edge of the Dynamic Panels Canvas, use the buttons next to "*Dock new panel to canvas:*". You can click a panel inside the preview zone (immediately under the *Docked Panels* section) and edit its tabs. You can also dock a panel to the selected panel using the buttons next to "*Dock new panel inside:*". 61 | 62 | When you are done, click the Play button to see the magic happen! 63 | 64 | There are a couple of settings in Dynamic Panels Canvas that you may want to tweak: 65 | 66 | - **Leave Free Space:** when enabled, there will always be some free space in the canvas that docked panels can't fill. Otherwise, docked panels will fill the whole canvas 67 | - **Minimum Free Space:** if *Leave Free Space* is enabled, this value will determine the minimum free space 68 | - **Free Space Target Transform:** if *Leave Free Space* is enabled and a RectTransform is assigned to this variable, the RectTransform's properties will automatically be updated to always match the free space's position and size 69 | - **Prevent Detaching Last Docked Panel:** when enabled, trying to detach the last docked panel from the canvas will automatically fail 70 | - **Panel Resizable Area Length:** size of the invisible resize zones at each side of the panels that allow users to resize the panels 71 | - **Canvas Anchor Zone Length:** size of the Dynamic Panels Canvas' drop zones. When a tab is dragged and dropped onto that area, it will be docked to that edge of the Dynamic Panels Canvas 72 | - **Panel Anchor Zone Length:** size of the panels' drop zones. When a tab is dragged and dropped onto that area, it will be docked to that panel. This area is enabled only for docked panels (you can't dock panels to free panels) 73 | - **Initial Size**: (*docked panels only*) determines the initial size of a docked panel. This is achieved by programmatically resizing the panel after it is created, so this operation may affect the adjacent panels' sizes, as well. This value won't have any effect if left as (0,0) 74 | 75 | **NOTE:** if you change the *Resources/DynamicPanel.prefab*, also make sure that the Panel's *Header Height* property is equal to the distance between the top of the panel and the bottom of the *PanelHeader* child object (which holds the tabs at runtime). 76 | 77 | ### PanelCursorHandler 78 | 79 | Adding this component to a GameObject will make the cursor dynamic i.e. its texture will change when it enters a panel's resizable area. 80 | 81 | ![dynamic_panels_canvas](Images/4_1.png) 82 | 83 | Note that this component won't have any effect on Android and iOS. 84 | 85 | ## SCRIPTING API 86 | 87 | Before using the scripting API, import **DynamicPanels** namespace to your script(s): `using DynamicPanels;` 88 | 89 | ### PanelUtils 90 | 91 | `static Panel CreatePanelFor( RectTransform content, DynamicPanelsCanvas canvas )`: creates and returns a panel with a tab that is associated with the *content*. The panel is created inside the specified Dynamic Panels Canvas. If the content is already part of a panel, then the existing panel is returned 92 | 93 | `static PanelTab GetAssociatedTab( RectTransform content )`: if *content* is associated with a tab, returns it; otherwise returns *null* 94 | 95 | ### Panel 96 | 97 | `DynamicPanelsCanvas Canvas { get; }`: returns the Dynamic Panels Canvas that this panel currently belongs to 98 | 99 | `PanelGroup Group { get; }`: returns the PanelGroup that this panel currently belongs to (more on that later) 100 | 101 | `Vector2 Position { get; }`: returns the anchored position of the panel. The anchor of a panel is located at its bottom-left corner 102 | 103 | `Vector2 Size { get; }`: returns the size of the panel 104 | 105 | `Vector2 MinSize { get; }`: returns the minimum size of the panel. This value is calculated at runtime using the minimum size values of the panel's tab(s) 106 | 107 | `int NumberOfTabs { get; }`: returns the number of tabs the panel has 108 | 109 | `int ActiveTab { get; set; }`: returns the index of the currently selected tab. Its value can be changed, as well 110 | 111 | `PanelTab this[int tabIndex] { get; }`: returns the tab at the specified index 112 | 113 | `bool IsDocked { get; } }`: returns whether the panel is a docked panel or a free panel 114 | 115 | `PanelTab AddTab( RectTransform tabContent, int tabIndex = -1 )`: adds a new tab to the panel and sets *tabContent* as its content. If *tabIndex* is not specified, then the tab will be inserted at the end of the tabs list. Newly created tabs will have default label/icon/minimum size values, so it is highly recommended to customize these values afterwards 116 | 117 | `PanelTab AddTab( PanelTab tab, int tabIndex = -1 )`: moves the specified tab to this panel 118 | 119 | `PanelTab AddTab( string tabID, int tabIndex = -1 )`: same as above 120 | 121 | `void RemoveTab( int tabIndex )`: removes a tab from the panel. Be careful when calling this function because the content associated with the tab will also be destroyed! 122 | 123 | `void RemoveTab( PanelTab tab )`: same as above 124 | 125 | `void RemoveTab( string tabID )`: same as above 126 | 127 | `int GetTabIndex( RectTransform tabContent )`: returns the index of a tab, or -1 if the tab is not part of the panel 128 | 129 | `int GetTabIndex( PanelTab tab )`: same as above 130 | 131 | `int GetTabIndex( string tabID )`: same as above 132 | 133 | `PanelTab GetTab( RectTransform tabContent )`: returns the tab that is associated with *tabContent*, or *null* if it is not a part of the panel 134 | 135 | `void DockToRoot( Direction direction )`: docks the panel to an edge of the Dynamic Panels Canvas 136 | 137 | `void DockToPanel( IPanelGroupElement anchor, Direction direction )`: docks the panel to another panel or panel group. It is not possible to dock a panel to a free panel 138 | 139 | `void Detach()`: if the panel is docked, detaches it so that it becomes a free panel 140 | 141 | `Panel DetachTab( int tabIndex )`: detaches a tab from the panel, creates a new panel with it and returns the new panel. If the tab is the only tab that the panel has, then the panel itself is detached and returned 142 | 143 | `Panel DetachTab( PanelTab tab )`: same as above 144 | 145 | `Panel DetachTab( string tabID )`: same as above 146 | 147 | `void BringForward()`: if the panel is free, brings it forwards so that it is drawn above all other panels 148 | 149 | `void MoveTo( Vector2 screenPoint )`: moves the panel to the specified point on the screen (panel's center will be aligned to the point) 150 | 151 | `void ResizeTo( Vector2 newSize )`: resizes the panel. If it is docked, then this change may also affect the adjacent panels 152 | 153 | `bool CanResizeInDirection( Direction direction )`: returns whether or not the panel can be resized in the specified direction 154 | 155 | `IPanelGroupElement GetSurroundingElement( Direction direction )`: if the panel is docked and if there is a panel/panel group in its specified vicinity, returns it 156 | 157 | ### PanelTab 158 | 159 | `string ID { get; set; }`: a unique identifier for this tab. It is mainly used in the serialization system but it can also be used to quickly access the tab via *PanelNotificationCenter.TryGetTab*. To view/change a tab's ID from the Inspector, right click the DynamicPanelsCanvas component and select "*Toggle Show IDs*" 160 | 161 | `Panel Panel { get; }`: returns the panel that the tab belongs to 162 | 163 | `int Index { get; set; }`: returns the index of the tab among all tabs on the panel. Its value can be changed 164 | 165 | `RectTransform Content { get; }`: returns the content (RectTransform) that is associated with the tab 166 | 167 | `Vector2 MinSize { get; set; }`: minimum size of the content 168 | 169 | `Sprite Icon { get; set; }`: the icon of the tab 170 | 171 | `string Label { get; set; }`: label of the tab 172 | 173 | `void AttachTo( Panel panel, int tabIndex = -1 )`: same as *Panel.AddTab* 174 | 175 | `Panel Detach()`: same as *Panel.DetachTab* 176 | 177 | `void Destroy()`: same as *Panel.RemoveTab* 178 | 179 | ### PanelGroup 180 | 181 | Panel groups are used to hold docked panels together. In a complex hierarchy, a panel group can have child panel groups, as well. A panel group can be either horizontal or vertical. After a panel group is created and populated, it should be docked to an already docked panel or panel group to be a part of the layout. 182 | 183 | `PanelGroup( DynamicPanelsCanvas canvas, Direction direction )`: creates a new panel group inside the specified DynamicPanelsCanvas. A *Left* or *Right* **direction** means a horizontal group, whereas a *Top* or *Bottom* direction means a vertical group. Panels in horizontal groups are always arranged from left to right and panels in vertical groups are always arranged from bottom to top; so it doesn't matter if the direction is Left or Right, or Top or Bottom. Just don't pass *None* here 184 | 185 | `DynamicPanelsCanvas Canvas { get; private set; }`: returns the Dynamic Panels Canvas that this group currently belongs to 186 | 187 | `PanelGroup Group { get; }`: returns the parent PanelGroup that this group currently belongs to. Each Dynamic Panels Canvas has a horizontal panel group at its root that is the root of all docked panels/panel groups in the layout. Free panels, on the other hand, belong to a special panel group called *UnanchoredPanelGroup*, which should never be touched 188 | 189 | `Vector2 Position { get; }`: returns the anchored position of the group. The anchor of a group is located at its bottom-left corner 190 | 191 | `Vector2 Size { get; }`: returns the size of the group 192 | 193 | `Vector2 MinSize { get; }`: returns the minimum size of the group. This value is calculated at runtime recursively using the minimum size values of the docked panels' tabs 194 | 195 | `int Count { get; }`: returns the number of elements (panels or child panel groups) in this group 196 | 197 | `IPanelGroupElement this[int index] { get; }`: returns the element at the specified index in this group 198 | 199 | `void AddElement( IPanelGroupElement element )`: adds an element to the end of the elements list. There is no *RemoveElement* function. Instead, when something changes in the layout (a panel is created/destroyed/moved between groups etc.), Dynamic Panels Canvas is notified and the whole layout is recalculated in *LateUpdate*. During this calculation, elements that belong to other groups are removed from their previous groups automatically 200 | 201 | `void AddElementBefore( IPanelGroupElement pivot, IPanelGroupElement element )`: inserts an element in front of a specified element in this group 202 | 203 | `void AddElementAfter( IPanelGroupElement pivot, IPanelGroupElement element )`: inserts an element after a specified element in this group 204 | 205 | `void DockToRoot( Direction direction )`: docks the panel group to an edge of the Dynamic Panels Canvas 206 | 207 | `void DockToPanel( IPanelGroupElement anchor, Direction direction )`: docks the panel group to another panel or panel group. It is not possible to dock a panel group to a free panel 208 | 209 | `void ResizeTo( Vector2 newSize )`: resizes the panel group. This change affects the panels inside the group and may also affect the adjacent panels. Make sure to dock the panel group to an element in the layout before calling this function 210 | 211 | `bool IsInSameDirection( Direction direction )`: if this group is horizontal, returns *true* if *direction* is Left or Right. Otherwise, returns *true* if *direction* is Top or Bottom 212 | 213 | `IPanelGroupElement GetSurroundingElement( Direction direction )`: if there is an element in the group's specified vicinity, returns it 214 | 215 | `void PrintHierarchy()`: prints the hierarchical tree of this group to the console. May be useful for debugging purposes 216 | 217 | ### DynamicPanelsCanvas 218 | 219 | `string ID { get; set; }`: a unique identifier for this canvas. It is used in the serialization system 220 | 221 | `void ForceRebuildLayoutImmediate()`: immediately rebuilds the layout of the Dynamic Panels Canvas, if it is dirty. This process involves a couple of steps: elements in groups are validated (elements that no longer belong to that group are removed, empty child groups are deleted and etc.), minimum sizes are calculated, bounds of the elements are recalculated and so on. This step is quite processor intensive and therefore, is not called immediately when something changes. Rather, it is called on LateUpdate to process everything in a single batch (it is called only if something has changed). But there is a drawback: if you modify the layout via Scripting API, you won't be able to access the correct size/position/minimum size values of the layout elements (panels/panel groups) until LateUpdate. Similarly, you won't be able to resize the layout elements in the same frame that you modify them (resizes happen instantly and do not count as modification, but the layout should be up-to-date) or iterate through the elements of a panel group until LateUpdate. To solve this issue, you can simply call this function after modifying the layout to rebuild all layout elements inside the canvas immediately 222 | 223 | `void SaveLayout()`: shorthand for *PanelSerialization.SerializeCanvas* 224 | 225 | `void LoadLayout()`: shorthand for *PanelSerialization.DeserializeCanvas* 226 | 227 | ### PanelSerialization 228 | 229 | This helper class can save&load the layout of a dynamic canvas via binary serialization at runtime. In the serialized data, tabs are referenced by their IDs, so these IDs should remain consistent. To test serialization in Unity editor while in Play mode, right click the DynamicPanelsCanvas component and select "*Save Layout*" or "*Load Layout*". 230 | 231 | `static byte[] SerializeCanvasToArray( DynamicPanelsCanvas canvas )`: serializes the current state of the panels inside the canvas and returns the serialized data. You are responsible from storing this data in a storage 232 | 233 | `static void DeserializeCanvasFromArray( DynamicPanelsCanvas canvas, byte[] data )`: deserializes the serialized data and restores the saved state of the panels 234 | 235 | `static void SerializeCanvas( DynamicPanelsCanvas canvas )`: internally calls *SerializeCanvasToArray* and saves the data to *PlayerPrefs* (using the *ID* of the canvas as key) 236 | 237 | `static void DeserializeCanvas( DynamicPanelsCanvas canvas )`: if a saved data for the canvas exists in *PlayerPrefs*, loads it and then calls *DeserializeCanvasFromArray* internally 238 | 239 | ### PanelNotificationCenter 240 | 241 | Notification center raises certain events during panels' lifecycle. It also holds a reference to each alive panel and therefore, can be used to iterate over all panels conveniently. 242 | 243 | `static event PanelDelegate OnPanelCreated`: raised when a new panel is created. *PanelDelegate* takes a *Panel* parameter 244 | 245 | `static event PanelDelegate OnPanelDestroyed`: raised when a panel is destroyed 246 | 247 | `static event PanelDelegate OnPanelBecameActive`: raised when a panel becomes active in the hierarchy 248 | 249 | `static event PanelDelegate OnPanelBecameInactive`: raised when a panel becomes inactive in the hierarchy 250 | 251 | `static event PanelDelegate OnPanelClosed`: raised when a panel's close button is clicked. By default, panels' close buttons are hidden. Once a functions is registered to this event, close buttons will become visible. Note that the panel won't be destroyed automatically after clicking the close button, it is your job to implement panel close functionality according to your needs in the registered function(s) 252 | 253 | `static event TabDelegate OnTabCreated`: raised when a new tab is created. *TabDelegate* takes a *PanelTab* parameter 254 | 255 | `static event TabDelegate OnTabDestroyed`: raised when a new tab is destroyed 256 | 257 | `static event TabDelegate OnActiveTabChanged`: raised when a panel's active tab changes 258 | 259 | `static event TabDelegate OnStartedDraggingTab`: raised when user starts dragging a tab 260 | 261 | `static event TabDelegate OnStoppedDraggingTab`: raised when user stops dragging a tab or system force stops a drag operation 262 | 263 | `static event TabDelegate OnTabClosed`: raised when a tab's close button is clicked. By default, tabs' close buttons are hidden. Once a functions is registered to this event, close buttons will become visible. Note that the tab won't be destroyed automatically after clicking the close button, it is your job to implement tab close functionality according to your needs in the registered function(s) 264 | 265 | `static int NumberOfPanels { get; }`: returns the number of alive panels (including inactive panels) 266 | 267 | `static Panel GetPanel( int panelIndex )`: returns a panel (it can be inactive) 268 | 269 | `static bool TryGetTab( string tabID, out PanelTab tab )`: checks whether or not a tab with the specified ID exists and returns it in the *tab* parameter 270 | 271 | ## EXAMPLE CODE 272 | 273 | The following example code creates 3 panels -one with 2 tabs- and generates a L-shaped layout with them. The final output can be seen in the following picture: 274 | 275 | ![dynamic_panels_canvas](Images/5.png) 276 | 277 | ```csharp 278 | using UnityEngine; 279 | using DynamicPanels; 280 | 281 | public class PanelCreator : MonoBehaviour 282 | { 283 | public DynamicPanelsCanvas canvas; 284 | 285 | public RectTransform content1, content2, content3, content4; 286 | public string tabLabel1, tabLabel2, tabLabel3, tabLabel4; 287 | public Sprite tabIcon1, tabIcon2, tabIcon3, tabIcon4; 288 | 289 | void Start() 290 | { 291 | // Create 3 panels 292 | Panel panel1 = PanelUtils.CreatePanelFor( content1, canvas ); 293 | Panel panel2 = PanelUtils.CreatePanelFor( content2, canvas ); 294 | Panel panel3 = PanelUtils.CreatePanelFor( content3, canvas ); 295 | 296 | // Add a second tab to the first panel 297 | panel1.AddTab( content4 ); 298 | 299 | // Set the labels and the (optional) icons of the tabs 300 | panel1[0].Icon = tabIcon1; // first tab 301 | panel1[0].Label = tabLabel1; 302 | panel1[1].Icon = tabIcon4; // second tab 303 | panel1[1].Label = tabLabel4; 304 | 305 | panel2[0].Icon = tabIcon2; 306 | panel2[0].Label = tabLabel2; 307 | panel3[0].Icon = tabIcon3; 308 | panel3[0].Label = tabLabel3; 309 | 310 | // Set the minimum sizes of the contents associated with the tabs 311 | panel1[0].MinSize = new Vector2( 300f, 300f ); // first tab 312 | panel1[1].MinSize = new Vector2( 300f, 300f ); // second tab 313 | 314 | panel2[0].MinSize = new Vector2( 300f, 300f ); 315 | panel3[0].MinSize = new Vector2( 300f, 300f ); 316 | 317 | // Create a vertical panel group 318 | PanelGroup groupLeftVertical = new PanelGroup( canvas, Direction.Top ); // elements are always arranged from bottom to top 319 | groupLeftVertical.AddElement( panel1 ); // bottom panel 320 | groupLeftVertical.AddElement( panel2 ); // top panel 321 | 322 | // Dock the elements to the Dynamic Panels Canvas (the order is important) 323 | panel3.DockToRoot( Direction.Bottom ); 324 | groupLeftVertical.DockToRoot( Direction.Left ); 325 | 326 | // Rebuild the layout before attempting to resize elements or read their correct sizes/minimum sizes 327 | canvas.ForceRebuildLayoutImmediate(); 328 | 329 | // It is recommended to manually resize layout elements that are created by code and docked. 330 | // Otherwise, their sizes will not be deterministic. In this case, we are resizing them to their minimum size 331 | groupLeftVertical.ResizeTo( new Vector2( groupLeftVertical.MinSize.x, groupLeftVertical.Size.y ) ); 332 | panel3.ResizeTo( new Vector2( panel3.Size.x, panel3.MinSize.y ) ); 333 | } 334 | } 335 | ``` 336 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Süleyman Yasir KULA 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5a3e72f94e950a44c8dd03f56d95fd26 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Plugins.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 23b2b70209ed4cd4d8d662d8b2373497 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d64fcc2c5c083934bb9a83e5e5693f36 3 | folderAsset: yes 4 | timeCreated: 1505604041 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: dec2ff6bcde25404e8b08e47281324f4 3 | folderAsset: yes 4 | timeCreated: 1550698230 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeHorizontal.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Cursors/CursorResizeHorizontal.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeHorizontal.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a9c77eeb970c9ae40a370ca7060be120 3 | timeCreated: 1550692045 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 1 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 7 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 32 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 32 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: Android 70 | maxTextureSize: 32 71 | textureFormat: -1 72 | textureCompression: 1 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: WebGL 78 | maxTextureSize: 32 79 | textureFormat: -1 80 | textureCompression: 1 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | spriteSheet: 86 | serializedVersion: 2 87 | sprites: [] 88 | outline: [] 89 | spritePackingTag: 90 | userData: 91 | assetBundleName: 92 | assetBundleVariant: 93 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeTopLeft.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Cursors/CursorResizeTopLeft.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeTopLeft.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cbaa205f7a905b8429011ee0c50015ea 3 | timeCreated: 1550692045 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 1 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 7 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 32 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 32 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: Android 70 | maxTextureSize: 32 71 | textureFormat: -1 72 | textureCompression: 1 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: WebGL 78 | maxTextureSize: 32 79 | textureFormat: -1 80 | textureCompression: 1 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | spriteSheet: 86 | serializedVersion: 2 87 | sprites: [] 88 | outline: [] 89 | spritePackingTag: 90 | userData: 91 | assetBundleName: 92 | assetBundleVariant: 93 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeTopRight.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Cursors/CursorResizeTopRight.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeTopRight.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e5a757b3ef912a24c912a99d9e1befe5 3 | timeCreated: 1550692045 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 1 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 7 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 32 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 32 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: Android 70 | maxTextureSize: 32 71 | textureFormat: -1 72 | textureCompression: 1 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: WebGL 78 | maxTextureSize: 32 79 | textureFormat: -1 80 | textureCompression: 1 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | spriteSheet: 86 | serializedVersion: 2 87 | sprites: [] 88 | outline: [] 89 | spritePackingTag: 90 | userData: 91 | assetBundleName: 92 | assetBundleVariant: 93 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeVertical.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Cursors/CursorResizeVertical.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Cursors/CursorResizeVertical.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 68ac78481f5b6df4da69a6f5133b6702 3 | timeCreated: 1550692045 4 | licenseType: Free 5 | TextureImporter: 6 | fileIDToRecycleName: {} 7 | serializedVersion: 4 8 | mipmaps: 9 | mipMapMode: 0 10 | enableMipMap: 0 11 | sRGBTexture: 0 12 | linearTexture: 0 13 | fadeOut: 0 14 | borderMipMap: 0 15 | mipMapFadeDistanceStart: 1 16 | mipMapFadeDistanceEnd: 3 17 | bumpmap: 18 | convertToNormalMap: 0 19 | externalNormalMap: 0 20 | heightScale: 0.25 21 | normalMapFilter: 0 22 | isReadable: 1 23 | grayScaleToAlpha: 0 24 | generateCubemap: 6 25 | cubemapConvolution: 0 26 | seamlessCubemap: 0 27 | textureFormat: 1 28 | maxTextureSize: 2048 29 | textureSettings: 30 | filterMode: 0 31 | aniso: 1 32 | mipBias: -1 33 | wrapMode: 1 34 | nPOTScale: 0 35 | lightmap: 0 36 | compressionQuality: 50 37 | spriteMode: 0 38 | spriteExtrude: 1 39 | spriteMeshType: 1 40 | alignment: 0 41 | spritePivot: {x: 0.5, y: 0.5} 42 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 43 | spritePixelsToUnits: 100 44 | alphaUsage: 1 45 | alphaIsTransparency: 1 46 | spriteTessellationDetail: -1 47 | textureType: 7 48 | textureShape: 1 49 | maxTextureSizeSet: 0 50 | compressionQualitySet: 0 51 | textureFormatSet: 0 52 | platformSettings: 53 | - buildTarget: DefaultTexturePlatform 54 | maxTextureSize: 32 55 | textureFormat: -1 56 | textureCompression: 1 57 | compressionQuality: 50 58 | crunchedCompression: 0 59 | allowsAlphaSplitting: 0 60 | overridden: 0 61 | - buildTarget: Standalone 62 | maxTextureSize: 32 63 | textureFormat: -1 64 | textureCompression: 1 65 | compressionQuality: 50 66 | crunchedCompression: 0 67 | allowsAlphaSplitting: 0 68 | overridden: 0 69 | - buildTarget: Android 70 | maxTextureSize: 32 71 | textureFormat: -1 72 | textureCompression: 1 73 | compressionQuality: 50 74 | crunchedCompression: 0 75 | allowsAlphaSplitting: 0 76 | overridden: 0 77 | - buildTarget: WebGL 78 | maxTextureSize: 32 79 | textureFormat: -1 80 | textureCompression: 1 81 | compressionQuality: 50 82 | crunchedCompression: 0 83 | allowsAlphaSplitting: 0 84 | overridden: 0 85 | spriteSheet: 86 | serializedVersion: 2 87 | sprites: [] 88 | outline: [] 89 | spritePackingTag: 90 | userData: 91 | assetBundleName: 92 | assetBundleVariant: 93 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/DemoScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e281fe27261b1da49893c13d99a44b97 3 | timeCreated: 1505604062 4 | licenseType: Free 5 | DefaultImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/DynamicPanels.Runtime.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DynamicPanels.Runtime", 3 | "references": [ 4 | "Unity.InputSystem" 5 | ] 6 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/DynamicPanels.Runtime.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 47588e3d37f573d458b0eaa6cc8109c2 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 05ed54b377aa11a44b72e14f82f44322 3 | folderAsset: yes 4 | timeCreated: 1521749988 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Editor/DynamicPanels.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DynamicPanels.Editor", 3 | "references": [ 4 | "DynamicPanels.Runtime" 5 | ], 6 | "includePlatforms": [ 7 | "Editor" 8 | ], 9 | "excludePlatforms": [], 10 | "allowUnsafeCode": false, 11 | "overrideReferences": false, 12 | "precompiledReferences": [], 13 | "autoReferenced": true, 14 | "defineConstraints": [], 15 | "versionDefines": [], 16 | "noEngineReferences": false 17 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Editor/DynamicPanels.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 57745fdc21e824f47b72f67cbb7c540b 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Editor/DynamicPanelsCanvasEditor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7c8e270c62c72c248941d2540e564a35 3 | timeCreated: 1521751306 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/README.txt: -------------------------------------------------------------------------------- 1 | = Dynamic Panels (v1.3.3) = 2 | 3 | Documentation: https://github.com/yasirkula/UnityDynamicPanels 4 | FAQ: https://github.com/yasirkula/UnityDynamicPanels#faq 5 | Example code: https://github.com/yasirkula/UnityDynamicPanels#example-code 6 | E-mail: yasirkula@gmail.com -------------------------------------------------------------------------------- /Plugins/DynamicPanels/README.txt.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 829a1f7aeff870a468a7bfbacc1d40be 3 | timeCreated: 1563308465 4 | licenseType: Free 5 | TextScriptImporter: 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a10da257b412cea428dfd530dbca2051 3 | folderAsset: yes 4 | timeCreated: 1504700276 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources/DynamicPanel.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1726343141212444} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1043796585229992 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 5 20 | m_Component: 21 | - component: {fileID: 224210798838178700} 22 | - component: {fileID: 222986914798992642} 23 | - component: {fileID: 114027493792779984} 24 | - component: {fileID: 114270162404285248} 25 | m_Layer: 5 26 | m_Name: CloseButton 27 | m_TagString: Untagged 28 | m_Icon: {fileID: 0} 29 | m_NavMeshLayer: 0 30 | m_StaticEditorFlags: 0 31 | m_IsActive: 0 32 | --- !u!1 &1114860203056810 33 | GameObject: 34 | m_ObjectHideFlags: 0 35 | m_PrefabParentObject: {fileID: 0} 36 | m_PrefabInternal: {fileID: 100100000} 37 | serializedVersion: 5 38 | m_Component: 39 | - component: {fileID: 224556564501171762} 40 | - component: {fileID: 222131658675741116} 41 | - component: {fileID: 114796528486332184} 42 | m_Layer: 5 43 | m_Name: Content 44 | m_TagString: Untagged 45 | m_Icon: {fileID: 0} 46 | m_NavMeshLayer: 0 47 | m_StaticEditorFlags: 0 48 | m_IsActive: 1 49 | --- !u!1 &1250567033053838 50 | GameObject: 51 | m_ObjectHideFlags: 0 52 | m_PrefabParentObject: {fileID: 0} 53 | m_PrefabInternal: {fileID: 100100000} 54 | serializedVersion: 5 55 | m_Component: 56 | - component: {fileID: 224099754535828374} 57 | - component: {fileID: 222812680874205716} 58 | - component: {fileID: 114206482443958740} 59 | - component: {fileID: 114082473048370878} 60 | - component: {fileID: 114377495251387228} 61 | m_Layer: 5 62 | m_Name: PanelHeader 63 | m_TagString: Untagged 64 | m_Icon: {fileID: 0} 65 | m_NavMeshLayer: 0 66 | m_StaticEditorFlags: 0 67 | m_IsActive: 1 68 | --- !u!1 &1726343141212444 69 | GameObject: 70 | m_ObjectHideFlags: 0 71 | m_PrefabParentObject: {fileID: 0} 72 | m_PrefabInternal: {fileID: 100100000} 73 | serializedVersion: 5 74 | m_Component: 75 | - component: {fileID: 224363748066174280} 76 | - component: {fileID: 222119064064416652} 77 | - component: {fileID: 225255291005751456} 78 | - component: {fileID: 114614089418798928} 79 | - component: {fileID: 114843194787698652} 80 | m_Layer: 5 81 | m_Name: DynamicPanel 82 | m_TagString: Untagged 83 | m_Icon: {fileID: 0} 84 | m_NavMeshLayer: 0 85 | m_StaticEditorFlags: 0 86 | m_IsActive: 1 87 | --- !u!114 &114027493792779984 88 | MonoBehaviour: 89 | m_ObjectHideFlags: 1 90 | m_PrefabParentObject: {fileID: 0} 91 | m_PrefabInternal: {fileID: 100100000} 92 | m_GameObject: {fileID: 1043796585229992} 93 | m_Enabled: 1 94 | m_EditorHideFlags: 0 95 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 96 | m_Name: 97 | m_EditorClassIdentifier: 98 | m_Material: {fileID: 0} 99 | m_Color: {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 1} 100 | m_RaycastTarget: 1 101 | m_OnCullStateChanged: 102 | m_PersistentCalls: 103 | m_Calls: [] 104 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 105 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 106 | m_Sprite: {fileID: 21300000, guid: 20c417e04b8c35f4091523662474a6c4, type: 3} 107 | m_Type: 0 108 | m_PreserveAspect: 0 109 | m_FillCenter: 1 110 | m_FillMethod: 4 111 | m_FillAmount: 1 112 | m_FillClockwise: 1 113 | m_FillOrigin: 0 114 | --- !u!114 &114082473048370878 115 | MonoBehaviour: 116 | m_ObjectHideFlags: 1 117 | m_PrefabParentObject: {fileID: 0} 118 | m_PrefabInternal: {fileID: 100100000} 119 | m_GameObject: {fileID: 1250567033053838} 120 | m_Enabled: 1 121 | m_EditorHideFlags: 0 122 | m_Script: {fileID: 11500000, guid: 034581b0eae396a48b005bc2114633f2, type: 3} 123 | m_Name: 124 | m_EditorClassIdentifier: 125 | m_panel: {fileID: 114843194787698652} 126 | --- !u!114 &114206482443958740 127 | MonoBehaviour: 128 | m_ObjectHideFlags: 1 129 | m_PrefabParentObject: {fileID: 0} 130 | m_PrefabInternal: {fileID: 100100000} 131 | m_GameObject: {fileID: 1250567033053838} 132 | m_Enabled: 1 133 | m_EditorHideFlags: 0 134 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 135 | m_Name: 136 | m_EditorClassIdentifier: 137 | m_Material: {fileID: 0} 138 | m_Color: {r: 0.2794118, g: 0.2794118, b: 0.2794118, a: 1} 139 | m_RaycastTarget: 1 140 | m_OnCullStateChanged: 141 | m_PersistentCalls: 142 | m_Calls: [] 143 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 144 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 145 | m_Sprite: {fileID: 21300000, guid: 7143c7559b82cd14da677a36b3df8d4d, type: 3} 146 | m_Type: 1 147 | m_PreserveAspect: 0 148 | m_FillCenter: 1 149 | m_FillMethod: 4 150 | m_FillAmount: 1 151 | m_FillClockwise: 1 152 | m_FillOrigin: 0 153 | --- !u!114 &114270162404285248 154 | MonoBehaviour: 155 | m_ObjectHideFlags: 1 156 | m_PrefabParentObject: {fileID: 0} 157 | m_PrefabInternal: {fileID: 100100000} 158 | m_GameObject: {fileID: 1043796585229992} 159 | m_Enabled: 1 160 | m_EditorHideFlags: 0 161 | m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3} 162 | m_Name: 163 | m_EditorClassIdentifier: 164 | m_Navigation: 165 | m_Mode: 0 166 | m_SelectOnUp: {fileID: 0} 167 | m_SelectOnDown: {fileID: 0} 168 | m_SelectOnLeft: {fileID: 0} 169 | m_SelectOnRight: {fileID: 0} 170 | m_Transition: 1 171 | m_Colors: 172 | m_NormalColor: {r: 1, g: 1, b: 1, a: 1} 173 | m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} 174 | m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} 175 | m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} 176 | m_ColorMultiplier: 1 177 | m_FadeDuration: 0.1 178 | m_SpriteState: 179 | m_HighlightedSprite: {fileID: 0} 180 | m_PressedSprite: {fileID: 0} 181 | m_DisabledSprite: {fileID: 0} 182 | m_AnimationTriggers: 183 | m_NormalTrigger: Normal 184 | m_HighlightedTrigger: Highlighted 185 | m_PressedTrigger: Pressed 186 | m_DisabledTrigger: Disabled 187 | m_Interactable: 1 188 | m_TargetGraphic: {fileID: 114027493792779984} 189 | m_OnClick: 190 | m_PersistentCalls: 191 | m_Calls: [] 192 | m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, 193 | Culture=neutral, PublicKeyToken=null 194 | --- !u!114 &114377495251387228 195 | MonoBehaviour: 196 | m_ObjectHideFlags: 1 197 | m_PrefabParentObject: {fileID: 0} 198 | m_PrefabInternal: {fileID: 100100000} 199 | m_GameObject: {fileID: 1250567033053838} 200 | m_Enabled: 1 201 | m_EditorHideFlags: 0 202 | m_Script: {fileID: -405508275, guid: f70555f144d8491a825f0804e09c671c, type: 3} 203 | m_Name: 204 | m_EditorClassIdentifier: 205 | m_Padding: 206 | m_Left: 0 207 | m_Right: 0 208 | m_Top: 10 209 | m_Bottom: 0 210 | m_ChildAlignment: 0 211 | m_Spacing: 0 212 | m_ChildForceExpandWidth: 0 213 | m_ChildForceExpandHeight: 1 214 | m_ChildControlWidth: 1 215 | m_ChildControlHeight: 1 216 | --- !u!114 &114614089418798928 217 | MonoBehaviour: 218 | m_ObjectHideFlags: 1 219 | m_PrefabParentObject: {fileID: 0} 220 | m_PrefabInternal: {fileID: 100100000} 221 | m_GameObject: {fileID: 1726343141212444} 222 | m_Enabled: 1 223 | m_EditorHideFlags: 0 224 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 225 | m_Name: 226 | m_EditorClassIdentifier: 227 | m_Material: {fileID: 0} 228 | m_Color: {r: 0.2784314, g: 0.2784314, b: 0.2784314, a: 1} 229 | m_RaycastTarget: 1 230 | m_OnCullStateChanged: 231 | m_PersistentCalls: 232 | m_Calls: [] 233 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 234 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 235 | m_Sprite: {fileID: 21300000, guid: 7143c7559b82cd14da677a36b3df8d4d, type: 3} 236 | m_Type: 1 237 | m_PreserveAspect: 0 238 | m_FillCenter: 1 239 | m_FillMethod: 4 240 | m_FillAmount: 1 241 | m_FillClockwise: 1 242 | m_FillOrigin: 0 243 | --- !u!114 &114796528486332184 244 | MonoBehaviour: 245 | m_ObjectHideFlags: 1 246 | m_PrefabParentObject: {fileID: 0} 247 | m_PrefabInternal: {fileID: 100100000} 248 | m_GameObject: {fileID: 1114860203056810} 249 | m_Enabled: 1 250 | m_EditorHideFlags: 0 251 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 252 | m_Name: 253 | m_EditorClassIdentifier: 254 | m_Material: {fileID: 0} 255 | m_Color: {r: 0.32352942, g: 0.32352942, b: 0.32352942, a: 1} 256 | m_RaycastTarget: 1 257 | m_OnCullStateChanged: 258 | m_PersistentCalls: 259 | m_Calls: [] 260 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 261 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 262 | m_Sprite: {fileID: 21300000, guid: 7143c7559b82cd14da677a36b3df8d4d, type: 3} 263 | m_Type: 1 264 | m_PreserveAspect: 0 265 | m_FillCenter: 1 266 | m_FillMethod: 4 267 | m_FillAmount: 1 268 | m_FillClockwise: 1 269 | m_FillOrigin: 0 270 | --- !u!114 &114843194787698652 271 | MonoBehaviour: 272 | m_ObjectHideFlags: 1 273 | m_PrefabParentObject: {fileID: 0} 274 | m_PrefabInternal: {fileID: 100100000} 275 | m_GameObject: {fileID: 1726343141212444} 276 | m_Enabled: 1 277 | m_EditorHideFlags: 0 278 | m_Script: {fileID: 11500000, guid: d12fb16f32dbe264e825a678eff38a90, type: 3} 279 | m_Name: 280 | m_EditorClassIdentifier: 281 | header: {fileID: 114082473048370878} 282 | tabsParent: {fileID: 224099754535828374} 283 | contentParent: {fileID: 224556564501171762} 284 | closeButton: {fileID: 114270162404285248} 285 | headerHeight: 42 286 | m_tabNormalColor: {r: 0.2784314, g: 0.2784314, b: 0.2784314, a: 1} 287 | m_tabNormalTextColor: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1} 288 | m_tabSelectedColor: {r: 0.375, g: 0.375, b: 0.375, a: 1} 289 | m_tabSelectedTextColor: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1} 290 | m_tabDetachingColor: {r: 0, g: 0.4855985, b: 0.5294118, a: 1} 291 | m_tabDetachingTextColor: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1} 292 | --- !u!222 &222119064064416652 293 | CanvasRenderer: 294 | m_ObjectHideFlags: 1 295 | m_PrefabParentObject: {fileID: 0} 296 | m_PrefabInternal: {fileID: 100100000} 297 | m_GameObject: {fileID: 1726343141212444} 298 | --- !u!222 &222131658675741116 299 | CanvasRenderer: 300 | m_ObjectHideFlags: 1 301 | m_PrefabParentObject: {fileID: 0} 302 | m_PrefabInternal: {fileID: 100100000} 303 | m_GameObject: {fileID: 1114860203056810} 304 | --- !u!222 &222812680874205716 305 | CanvasRenderer: 306 | m_ObjectHideFlags: 1 307 | m_PrefabParentObject: {fileID: 0} 308 | m_PrefabInternal: {fileID: 100100000} 309 | m_GameObject: {fileID: 1250567033053838} 310 | --- !u!222 &222986914798992642 311 | CanvasRenderer: 312 | m_ObjectHideFlags: 1 313 | m_PrefabParentObject: {fileID: 0} 314 | m_PrefabInternal: {fileID: 100100000} 315 | m_GameObject: {fileID: 1043796585229992} 316 | --- !u!224 &224099754535828374 317 | RectTransform: 318 | m_ObjectHideFlags: 1 319 | m_PrefabParentObject: {fileID: 0} 320 | m_PrefabInternal: {fileID: 100100000} 321 | m_GameObject: {fileID: 1250567033053838} 322 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 323 | m_LocalPosition: {x: 0, y: 0, z: 0} 324 | m_LocalScale: {x: 1, y: 1, z: 1} 325 | m_Children: [] 326 | m_Father: {fileID: 224363748066174280} 327 | m_RootOrder: 1 328 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 329 | m_AnchorMin: {x: 0, y: 1} 330 | m_AnchorMax: {x: 1, y: 1} 331 | m_AnchoredPosition: {x: 2, y: -2} 332 | m_SizeDelta: {x: -4, y: 40} 333 | m_Pivot: {x: 0, y: 1} 334 | --- !u!224 &224210798838178700 335 | RectTransform: 336 | m_ObjectHideFlags: 1 337 | m_PrefabParentObject: {fileID: 0} 338 | m_PrefabInternal: {fileID: 100100000} 339 | m_GameObject: {fileID: 1043796585229992} 340 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 341 | m_LocalPosition: {x: 0, y: 0, z: 0} 342 | m_LocalScale: {x: 1, y: 1, z: 1} 343 | m_Children: [] 344 | m_Father: {fileID: 224363748066174280} 345 | m_RootOrder: 2 346 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 347 | m_AnchorMin: {x: 1, y: 1} 348 | m_AnchorMax: {x: 1, y: 1} 349 | m_AnchoredPosition: {x: -2, y: -2} 350 | m_SizeDelta: {x: 20, y: 20} 351 | m_Pivot: {x: 1, y: 1} 352 | --- !u!224 &224363748066174280 353 | RectTransform: 354 | m_ObjectHideFlags: 1 355 | m_PrefabParentObject: {fileID: 0} 356 | m_PrefabInternal: {fileID: 100100000} 357 | m_GameObject: {fileID: 1726343141212444} 358 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 359 | m_LocalPosition: {x: 0, y: 0, z: 0} 360 | m_LocalScale: {x: 1, y: 1, z: 1} 361 | m_Children: 362 | - {fileID: 224556564501171762} 363 | - {fileID: 224099754535828374} 364 | - {fileID: 224210798838178700} 365 | m_Father: {fileID: 0} 366 | m_RootOrder: 0 367 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 368 | m_AnchorMin: {x: 0, y: 0} 369 | m_AnchorMax: {x: 0, y: 0} 370 | m_AnchoredPosition: {x: 400, y: 100} 371 | m_SizeDelta: {x: 250, y: 500} 372 | m_Pivot: {x: 0, y: 0} 373 | --- !u!224 &224556564501171762 374 | RectTransform: 375 | m_ObjectHideFlags: 1 376 | m_PrefabParentObject: {fileID: 0} 377 | m_PrefabInternal: {fileID: 100100000} 378 | m_GameObject: {fileID: 1114860203056810} 379 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 380 | m_LocalPosition: {x: 0, y: 0, z: 0} 381 | m_LocalScale: {x: 1, y: 1, z: 1} 382 | m_Children: [] 383 | m_Father: {fileID: 224363748066174280} 384 | m_RootOrder: 0 385 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 386 | m_AnchorMin: {x: 0, y: 0} 387 | m_AnchorMax: {x: 1, y: 1} 388 | m_AnchoredPosition: {x: 0, y: -20} 389 | m_SizeDelta: {x: -4, y: -44} 390 | m_Pivot: {x: 0.5, y: 0.5} 391 | --- !u!225 &225255291005751456 392 | CanvasGroup: 393 | m_ObjectHideFlags: 1 394 | m_PrefabParentObject: {fileID: 0} 395 | m_PrefabInternal: {fileID: 100100000} 396 | m_GameObject: {fileID: 1726343141212444} 397 | m_Enabled: 1 398 | m_Alpha: 1 399 | m_Interactable: 1 400 | m_BlocksRaycasts: 1 401 | m_IgnoreParentGroups: 0 402 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources/DynamicPanel.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5c4342897b6a5d94c9c583ef61af55f2 3 | timeCreated: 1504010371 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources/DynamicPanelPreview.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1726343141212444} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1726343141212444 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 5 20 | m_Component: 21 | - component: {fileID: 224363748066174280} 22 | - component: {fileID: 222119064064416652} 23 | - component: {fileID: 114614089418798928} 24 | m_Layer: 5 25 | m_Name: DynamicPanelPreview 26 | m_TagString: Untagged 27 | m_Icon: {fileID: 0} 28 | m_NavMeshLayer: 0 29 | m_StaticEditorFlags: 0 30 | m_IsActive: 1 31 | --- !u!114 &114614089418798928 32 | MonoBehaviour: 33 | m_ObjectHideFlags: 1 34 | m_PrefabParentObject: {fileID: 0} 35 | m_PrefabInternal: {fileID: 100100000} 36 | m_GameObject: {fileID: 1726343141212444} 37 | m_Enabled: 1 38 | m_EditorHideFlags: 0 39 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 40 | m_Name: 41 | m_EditorClassIdentifier: 42 | m_Material: {fileID: 0} 43 | m_Color: {r: 0, g: 0.4855985, b: 0.5294118, a: 0.572} 44 | m_RaycastTarget: 0 45 | m_OnCullStateChanged: 46 | m_PersistentCalls: 47 | m_Calls: [] 48 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 49 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 50 | m_Sprite: {fileID: 21300000, guid: ef24468435bb0d64296ede4cf9b6cc18, type: 3} 51 | m_Type: 1 52 | m_PreserveAspect: 0 53 | m_FillCenter: 1 54 | m_FillMethod: 4 55 | m_FillAmount: 1 56 | m_FillClockwise: 1 57 | m_FillOrigin: 0 58 | --- !u!222 &222119064064416652 59 | CanvasRenderer: 60 | m_ObjectHideFlags: 1 61 | m_PrefabParentObject: {fileID: 0} 62 | m_PrefabInternal: {fileID: 100100000} 63 | m_GameObject: {fileID: 1726343141212444} 64 | --- !u!224 &224363748066174280 65 | RectTransform: 66 | m_ObjectHideFlags: 1 67 | m_PrefabParentObject: {fileID: 0} 68 | m_PrefabInternal: {fileID: 100100000} 69 | m_GameObject: {fileID: 1726343141212444} 70 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 71 | m_LocalPosition: {x: 0, y: 0, z: 0} 72 | m_LocalScale: {x: 1, y: 1, z: 1} 73 | m_Children: [] 74 | m_Father: {fileID: 0} 75 | m_RootOrder: 0 76 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 77 | m_AnchorMin: {x: 0.5, y: 0.5} 78 | m_AnchorMax: {x: 0.5, y: 0.5} 79 | m_AnchoredPosition: {x: 0, y: 0} 80 | m_SizeDelta: {x: 250, y: 500} 81 | m_Pivot: {x: 0.5, y: 0.5} 82 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources/DynamicPanelPreview.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 55332d0ddeee7454095367b476b6813f 3 | timeCreated: 1504010371 4 | licenseType: Pro 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources/DynamicPanelTab.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1001 &100100000 4 | Prefab: 5 | m_ObjectHideFlags: 1 6 | serializedVersion: 2 7 | m_Modification: 8 | m_TransformParent: {fileID: 0} 9 | m_Modifications: [] 10 | m_RemovedComponents: [] 11 | m_ParentPrefab: {fileID: 0} 12 | m_RootGameObject: {fileID: 1818210840912162} 13 | m_IsPrefabParent: 1 14 | --- !u!1 &1223609383961532 15 | GameObject: 16 | m_ObjectHideFlags: 0 17 | m_PrefabParentObject: {fileID: 0} 18 | m_PrefabInternal: {fileID: 100100000} 19 | serializedVersion: 5 20 | m_Component: 21 | - component: {fileID: 224043261511920982} 22 | - component: {fileID: 114701449697720124} 23 | m_Layer: 5 24 | m_Name: TabContent 25 | m_TagString: Untagged 26 | m_Icon: {fileID: 0} 27 | m_NavMeshLayer: 0 28 | m_StaticEditorFlags: 0 29 | m_IsActive: 1 30 | --- !u!1 &1290506992397030 31 | GameObject: 32 | m_ObjectHideFlags: 1 33 | m_PrefabParentObject: {fileID: 0} 34 | m_PrefabInternal: {fileID: 100100000} 35 | serializedVersion: 5 36 | m_Component: 37 | - component: {fileID: 224621675957088348} 38 | - component: {fileID: 222740463014405626} 39 | - component: {fileID: 114148454421488184} 40 | - component: {fileID: 114249787093205428} 41 | m_Layer: 5 42 | m_Name: IconHolder 43 | m_TagString: Untagged 44 | m_Icon: {fileID: 0} 45 | m_NavMeshLayer: 0 46 | m_StaticEditorFlags: 0 47 | m_IsActive: 1 48 | --- !u!1 &1372674879344126 49 | GameObject: 50 | m_ObjectHideFlags: 1 51 | m_PrefabParentObject: {fileID: 0} 52 | m_PrefabInternal: {fileID: 100100000} 53 | serializedVersion: 5 54 | m_Component: 55 | - component: {fileID: 224736951175262904} 56 | - component: {fileID: 222039814760231978} 57 | - component: {fileID: 114355370929409690} 58 | - component: {fileID: 114202354710620052} 59 | m_Layer: 5 60 | m_Name: NameHolder 61 | m_TagString: Untagged 62 | m_Icon: {fileID: 0} 63 | m_NavMeshLayer: 0 64 | m_StaticEditorFlags: 0 65 | m_IsActive: 1 66 | --- !u!1 &1542935947266476 67 | GameObject: 68 | m_ObjectHideFlags: 1 69 | m_PrefabParentObject: {fileID: 0} 70 | m_PrefabInternal: {fileID: 100100000} 71 | serializedVersion: 5 72 | m_Component: 73 | - component: {fileID: 224500342738483090} 74 | - component: {fileID: 222597669491153042} 75 | - component: {fileID: 114765799510743192} 76 | - component: {fileID: 114670313046251076} 77 | - component: {fileID: 114740044306829198} 78 | m_Layer: 5 79 | m_Name: CloseButton 80 | m_TagString: Untagged 81 | m_Icon: {fileID: 0} 82 | m_NavMeshLayer: 0 83 | m_StaticEditorFlags: 0 84 | m_IsActive: 0 85 | --- !u!1 &1818210840912162 86 | GameObject: 87 | m_ObjectHideFlags: 0 88 | m_PrefabParentObject: {fileID: 0} 89 | m_PrefabInternal: {fileID: 100100000} 90 | serializedVersion: 5 91 | m_Component: 92 | - component: {fileID: 224452818132221032} 93 | - component: {fileID: 222162105973802306} 94 | - component: {fileID: 114017937663857124} 95 | - component: {fileID: 114250021572920576} 96 | - component: {fileID: 114042780021900062} 97 | m_Layer: 5 98 | m_Name: DynamicPanelTab 99 | m_TagString: Untagged 100 | m_Icon: {fileID: 0} 101 | m_NavMeshLayer: 0 102 | m_StaticEditorFlags: 0 103 | m_IsActive: 1 104 | --- !u!114 &114017937663857124 105 | MonoBehaviour: 106 | m_ObjectHideFlags: 1 107 | m_PrefabParentObject: {fileID: 0} 108 | m_PrefabInternal: {fileID: 100100000} 109 | m_GameObject: {fileID: 1818210840912162} 110 | m_Enabled: 1 111 | m_EditorHideFlags: 0 112 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 113 | m_Name: 114 | m_EditorClassIdentifier: 115 | m_Material: {fileID: 0} 116 | m_Color: {r: 0.9485294, g: 0.9485294, b: 0.9485294, a: 1} 117 | m_RaycastTarget: 1 118 | m_OnCullStateChanged: 119 | m_PersistentCalls: 120 | m_Calls: [] 121 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 122 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 123 | m_Sprite: {fileID: 21300000, guid: ef24468435bb0d64296ede4cf9b6cc18, type: 3} 124 | m_Type: 1 125 | m_PreserveAspect: 0 126 | m_FillCenter: 1 127 | m_FillMethod: 4 128 | m_FillAmount: 1 129 | m_FillClockwise: 1 130 | m_FillOrigin: 0 131 | --- !u!114 &114042780021900062 132 | MonoBehaviour: 133 | m_ObjectHideFlags: 1 134 | m_PrefabParentObject: {fileID: 0} 135 | m_PrefabInternal: {fileID: 100100000} 136 | m_GameObject: {fileID: 1818210840912162} 137 | m_Enabled: 1 138 | m_EditorHideFlags: 0 139 | m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} 140 | m_Name: 141 | m_EditorClassIdentifier: 142 | m_IgnoreLayout: 0 143 | m_MinWidth: -1 144 | m_MinHeight: -1 145 | m_PreferredWidth: 100 146 | m_PreferredHeight: -1 147 | m_FlexibleWidth: -1 148 | m_FlexibleHeight: -1 149 | --- !u!114 &114148454421488184 150 | MonoBehaviour: 151 | m_ObjectHideFlags: 1 152 | m_PrefabParentObject: {fileID: 0} 153 | m_PrefabInternal: {fileID: 100100000} 154 | m_GameObject: {fileID: 1290506992397030} 155 | m_Enabled: 1 156 | m_EditorHideFlags: 0 157 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 158 | m_Name: 159 | m_EditorClassIdentifier: 160 | m_Material: {fileID: 0} 161 | m_Color: {r: 1, g: 1, b: 1, a: 1} 162 | m_RaycastTarget: 0 163 | m_OnCullStateChanged: 164 | m_PersistentCalls: 165 | m_Calls: [] 166 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 167 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 168 | m_Sprite: {fileID: 21300000, guid: 7143c7559b82cd14da677a36b3df8d4d, type: 3} 169 | m_Type: 0 170 | m_PreserveAspect: 1 171 | m_FillCenter: 1 172 | m_FillMethod: 4 173 | m_FillAmount: 1 174 | m_FillClockwise: 1 175 | m_FillOrigin: 0 176 | --- !u!114 &114202354710620052 177 | MonoBehaviour: 178 | m_ObjectHideFlags: 1 179 | m_PrefabParentObject: {fileID: 0} 180 | m_PrefabInternal: {fileID: 100100000} 181 | m_GameObject: {fileID: 1372674879344126} 182 | m_Enabled: 1 183 | m_EditorHideFlags: 0 184 | m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} 185 | m_Name: 186 | m_EditorClassIdentifier: 187 | m_IgnoreLayout: 0 188 | m_MinWidth: -1 189 | m_MinHeight: -1 190 | m_PreferredWidth: -1 191 | m_PreferredHeight: -1 192 | m_FlexibleWidth: 1 193 | m_FlexibleHeight: -1 194 | --- !u!114 &114249787093205428 195 | MonoBehaviour: 196 | m_ObjectHideFlags: 1 197 | m_PrefabParentObject: {fileID: 0} 198 | m_PrefabInternal: {fileID: 100100000} 199 | m_GameObject: {fileID: 1290506992397030} 200 | m_Enabled: 1 201 | m_EditorHideFlags: 0 202 | m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} 203 | m_Name: 204 | m_EditorClassIdentifier: 205 | m_IgnoreLayout: 0 206 | m_MinWidth: -1 207 | m_MinHeight: -1 208 | m_PreferredWidth: 24 209 | m_PreferredHeight: -1 210 | m_FlexibleWidth: -1 211 | m_FlexibleHeight: -1 212 | --- !u!114 &114250021572920576 213 | MonoBehaviour: 214 | m_ObjectHideFlags: 1 215 | m_PrefabParentObject: {fileID: 0} 216 | m_PrefabInternal: {fileID: 100100000} 217 | m_GameObject: {fileID: 1818210840912162} 218 | m_Enabled: 1 219 | m_EditorHideFlags: 0 220 | m_Script: {fileID: 11500000, guid: 37df190a5f116af4d978c253e5f06d63, type: 3} 221 | m_Name: 222 | m_EditorClassIdentifier: 223 | background: {fileID: 114017937663857124} 224 | iconHolder: {fileID: 114148454421488184} 225 | nameHolder: {fileID: 114355370929409690} 226 | closeButton: {fileID: 114670313046251076} 227 | --- !u!114 &114355370929409690 228 | MonoBehaviour: 229 | m_ObjectHideFlags: 1 230 | m_PrefabParentObject: {fileID: 0} 231 | m_PrefabInternal: {fileID: 100100000} 232 | m_GameObject: {fileID: 1372674879344126} 233 | m_Enabled: 1 234 | m_EditorHideFlags: 0 235 | m_Script: {fileID: 708705254, guid: f70555f144d8491a825f0804e09c671c, type: 3} 236 | m_Name: 237 | m_EditorClassIdentifier: 238 | m_Material: {fileID: 0} 239 | m_Color: {r: 0.83823526, g: 0.84439874, b: 0.84439874, a: 1} 240 | m_RaycastTarget: 0 241 | m_OnCullStateChanged: 242 | m_PersistentCalls: 243 | m_Calls: [] 244 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 245 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 246 | m_FontData: 247 | m_Font: {fileID: 10102, guid: 0000000000000000e000000000000000, type: 0} 248 | m_FontSize: 14 249 | m_FontStyle: 0 250 | m_BestFit: 1 251 | m_MinSize: 10 252 | m_MaxSize: 14 253 | m_Alignment: 3 254 | m_AlignByGeometry: 0 255 | m_RichText: 1 256 | m_HorizontalOverflow: 0 257 | m_VerticalOverflow: 0 258 | m_LineSpacing: 1 259 | m_Text: Tab 260 | --- !u!114 &114670313046251076 261 | MonoBehaviour: 262 | m_ObjectHideFlags: 1 263 | m_PrefabParentObject: {fileID: 0} 264 | m_PrefabInternal: {fileID: 100100000} 265 | m_GameObject: {fileID: 1542935947266476} 266 | m_Enabled: 1 267 | m_EditorHideFlags: 0 268 | m_Script: {fileID: 1392445389, guid: f70555f144d8491a825f0804e09c671c, type: 3} 269 | m_Name: 270 | m_EditorClassIdentifier: 271 | m_Navigation: 272 | m_Mode: 0 273 | m_SelectOnUp: {fileID: 0} 274 | m_SelectOnDown: {fileID: 0} 275 | m_SelectOnLeft: {fileID: 0} 276 | m_SelectOnRight: {fileID: 0} 277 | m_Transition: 1 278 | m_Colors: 279 | m_NormalColor: {r: 1, g: 1, b: 1, a: 1} 280 | m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} 281 | m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} 282 | m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} 283 | m_ColorMultiplier: 1 284 | m_FadeDuration: 0.1 285 | m_SpriteState: 286 | m_HighlightedSprite: {fileID: 0} 287 | m_PressedSprite: {fileID: 0} 288 | m_DisabledSprite: {fileID: 0} 289 | m_AnimationTriggers: 290 | m_NormalTrigger: Normal 291 | m_HighlightedTrigger: Highlighted 292 | m_PressedTrigger: Pressed 293 | m_DisabledTrigger: Disabled 294 | m_Interactable: 1 295 | m_TargetGraphic: {fileID: 114765799510743192} 296 | m_OnClick: 297 | m_PersistentCalls: 298 | m_Calls: [] 299 | m_TypeName: UnityEngine.UI.Button+ButtonClickedEvent, UnityEngine.UI, Version=1.0.0.0, 300 | Culture=neutral, PublicKeyToken=null 301 | --- !u!114 &114701449697720124 302 | MonoBehaviour: 303 | m_ObjectHideFlags: 1 304 | m_PrefabParentObject: {fileID: 0} 305 | m_PrefabInternal: {fileID: 100100000} 306 | m_GameObject: {fileID: 1223609383961532} 307 | m_Enabled: 1 308 | m_EditorHideFlags: 0 309 | m_Script: {fileID: -405508275, guid: f70555f144d8491a825f0804e09c671c, type: 3} 310 | m_Name: 311 | m_EditorClassIdentifier: 312 | m_Padding: 313 | m_Left: 3 314 | m_Right: 3 315 | m_Top: 1 316 | m_Bottom: 1 317 | m_ChildAlignment: 0 318 | m_Spacing: 4 319 | m_ChildForceExpandWidth: 0 320 | m_ChildForceExpandHeight: 1 321 | m_ChildControlWidth: 1 322 | m_ChildControlHeight: 1 323 | --- !u!114 &114740044306829198 324 | MonoBehaviour: 325 | m_ObjectHideFlags: 1 326 | m_PrefabParentObject: {fileID: 0} 327 | m_PrefabInternal: {fileID: 100100000} 328 | m_GameObject: {fileID: 1542935947266476} 329 | m_Enabled: 1 330 | m_EditorHideFlags: 0 331 | m_Script: {fileID: 1679637790, guid: f70555f144d8491a825f0804e09c671c, type: 3} 332 | m_Name: 333 | m_EditorClassIdentifier: 334 | m_IgnoreLayout: 0 335 | m_MinWidth: 14 336 | m_MinHeight: -1 337 | m_PreferredWidth: 14 338 | m_PreferredHeight: -1 339 | m_FlexibleWidth: -1 340 | m_FlexibleHeight: -1 341 | --- !u!114 &114765799510743192 342 | MonoBehaviour: 343 | m_ObjectHideFlags: 1 344 | m_PrefabParentObject: {fileID: 0} 345 | m_PrefabInternal: {fileID: 100100000} 346 | m_GameObject: {fileID: 1542935947266476} 347 | m_Enabled: 1 348 | m_EditorHideFlags: 0 349 | m_Script: {fileID: -765806418, guid: f70555f144d8491a825f0804e09c671c, type: 3} 350 | m_Name: 351 | m_EditorClassIdentifier: 352 | m_Material: {fileID: 0} 353 | m_Color: {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 1} 354 | m_RaycastTarget: 1 355 | m_OnCullStateChanged: 356 | m_PersistentCalls: 357 | m_Calls: [] 358 | m_TypeName: UnityEngine.UI.MaskableGraphic+CullStateChangedEvent, UnityEngine.UI, 359 | Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 360 | m_Sprite: {fileID: 21300000, guid: 20c417e04b8c35f4091523662474a6c4, type: 3} 361 | m_Type: 0 362 | m_PreserveAspect: 1 363 | m_FillCenter: 1 364 | m_FillMethod: 4 365 | m_FillAmount: 1 366 | m_FillClockwise: 1 367 | m_FillOrigin: 0 368 | --- !u!222 &222039814760231978 369 | CanvasRenderer: 370 | m_ObjectHideFlags: 1 371 | m_PrefabParentObject: {fileID: 0} 372 | m_PrefabInternal: {fileID: 100100000} 373 | m_GameObject: {fileID: 1372674879344126} 374 | --- !u!222 &222162105973802306 375 | CanvasRenderer: 376 | m_ObjectHideFlags: 1 377 | m_PrefabParentObject: {fileID: 0} 378 | m_PrefabInternal: {fileID: 100100000} 379 | m_GameObject: {fileID: 1818210840912162} 380 | --- !u!222 &222597669491153042 381 | CanvasRenderer: 382 | m_ObjectHideFlags: 1 383 | m_PrefabParentObject: {fileID: 0} 384 | m_PrefabInternal: {fileID: 100100000} 385 | m_GameObject: {fileID: 1542935947266476} 386 | --- !u!222 &222740463014405626 387 | CanvasRenderer: 388 | m_ObjectHideFlags: 1 389 | m_PrefabParentObject: {fileID: 0} 390 | m_PrefabInternal: {fileID: 100100000} 391 | m_GameObject: {fileID: 1290506992397030} 392 | --- !u!224 &224043261511920982 393 | RectTransform: 394 | m_ObjectHideFlags: 1 395 | m_PrefabParentObject: {fileID: 0} 396 | m_PrefabInternal: {fileID: 100100000} 397 | m_GameObject: {fileID: 1223609383961532} 398 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 399 | m_LocalPosition: {x: 0, y: 0, z: 0} 400 | m_LocalScale: {x: 1, y: 1, z: 1} 401 | m_Children: 402 | - {fileID: 224621675957088348} 403 | - {fileID: 224736951175262904} 404 | - {fileID: 224500342738483090} 405 | m_Father: {fileID: 224452818132221032} 406 | m_RootOrder: 0 407 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 408 | m_AnchorMin: {x: 0, y: 0} 409 | m_AnchorMax: {x: 1, y: 1} 410 | m_AnchoredPosition: {x: 0, y: 0} 411 | m_SizeDelta: {x: 0, y: 0} 412 | m_Pivot: {x: 0.5, y: 0.5} 413 | --- !u!224 &224452818132221032 414 | RectTransform: 415 | m_ObjectHideFlags: 1 416 | m_PrefabParentObject: {fileID: 0} 417 | m_PrefabInternal: {fileID: 100100000} 418 | m_GameObject: {fileID: 1818210840912162} 419 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 420 | m_LocalPosition: {x: 0, y: 0, z: 0} 421 | m_LocalScale: {x: 1, y: 1, z: 1} 422 | m_Children: 423 | - {fileID: 224043261511920982} 424 | m_Father: {fileID: 0} 425 | m_RootOrder: 0 426 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 427 | m_AnchorMin: {x: 0, y: 0} 428 | m_AnchorMax: {x: 0, y: 0} 429 | m_AnchoredPosition: {x: 0, y: 0} 430 | m_SizeDelta: {x: 0, y: 0} 431 | m_Pivot: {x: 0, y: 0.5} 432 | --- !u!224 &224500342738483090 433 | RectTransform: 434 | m_ObjectHideFlags: 1 435 | m_PrefabParentObject: {fileID: 0} 436 | m_PrefabInternal: {fileID: 100100000} 437 | m_GameObject: {fileID: 1542935947266476} 438 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 439 | m_LocalPosition: {x: 0, y: 0, z: 0} 440 | m_LocalScale: {x: 1, y: 1, z: 1} 441 | m_Children: [] 442 | m_Father: {fileID: 224043261511920982} 443 | m_RootOrder: 2 444 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 445 | m_AnchorMin: {x: 0, y: 1} 446 | m_AnchorMax: {x: 0, y: 1} 447 | m_AnchoredPosition: {x: 97, y: -1} 448 | m_SizeDelta: {x: 14, y: 28} 449 | m_Pivot: {x: 1, y: 1} 450 | --- !u!224 &224621675957088348 451 | RectTransform: 452 | m_ObjectHideFlags: 1 453 | m_PrefabParentObject: {fileID: 0} 454 | m_PrefabInternal: {fileID: 100100000} 455 | m_GameObject: {fileID: 1290506992397030} 456 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 457 | m_LocalPosition: {x: 0, y: 0, z: 0} 458 | m_LocalScale: {x: 1, y: 1, z: 1} 459 | m_Children: [] 460 | m_Father: {fileID: 224043261511920982} 461 | m_RootOrder: 0 462 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 463 | m_AnchorMin: {x: 0, y: 0} 464 | m_AnchorMax: {x: 0, y: 0} 465 | m_AnchoredPosition: {x: 0, y: 0} 466 | m_SizeDelta: {x: 0, y: 0} 467 | m_Pivot: {x: 0, y: 0.5} 468 | --- !u!224 &224736951175262904 469 | RectTransform: 470 | m_ObjectHideFlags: 1 471 | m_PrefabParentObject: {fileID: 0} 472 | m_PrefabInternal: {fileID: 100100000} 473 | m_GameObject: {fileID: 1372674879344126} 474 | m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} 475 | m_LocalPosition: {x: 0, y: 0, z: 0} 476 | m_LocalScale: {x: 1, y: 1, z: 1} 477 | m_Children: [] 478 | m_Father: {fileID: 224043261511920982} 479 | m_RootOrder: 1 480 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 481 | m_AnchorMin: {x: 0, y: 0} 482 | m_AnchorMax: {x: 0, y: 0} 483 | m_AnchoredPosition: {x: 0, y: 0} 484 | m_SizeDelta: {x: 0, y: 0} 485 | m_Pivot: {x: 0.5, y: 0.5} 486 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Resources/DynamicPanelTab.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 020fbf96414a1a847aeb92aaea52178e 3 | timeCreated: 1521635861 4 | licenseType: Free 5 | NativeFormatImporter: 6 | mainObjectFileID: 100100000 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a149c9a845d61984190c902c74445984 3 | folderAsset: yes 4 | timeCreated: 1503931369 5 | licenseType: Pro 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b894fe9ea0f830343b87ef42f0290167 3 | folderAsset: yes 4 | timeCreated: 1521654151 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/AnchorZoneBase.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | using UnityEngine.UI; 4 | 5 | namespace DynamicPanels 6 | { 7 | [DisallowMultipleComponent] 8 | public abstract class AnchorZoneBase : MonoBehaviour, IPointerEnterHandler, IPointerDownHandler, IPointerExitHandler 9 | { 10 | protected Panel m_panel; 11 | public Panel Panel { get { return m_panel; } } 12 | 13 | public RectTransform RectTransform { get; private set; } 14 | 15 | private Graphic raycastZone; 16 | 17 | private int hoveredPointerId = PanelManager.NON_EXISTING_TOUCH; 18 | 19 | public DynamicPanelsCanvas Canvas { get { return m_panel.Canvas; } } 20 | 21 | protected void Awake() 22 | { 23 | RectTransform = (RectTransform) transform; 24 | raycastZone = gameObject.AddComponent(); 25 | } 26 | 27 | protected void OnEnable() 28 | { 29 | hoveredPointerId = PanelManager.NON_EXISTING_TOUCH; 30 | } 31 | 32 | public abstract bool Execute( PanelTab panelTab, PointerEventData eventData ); 33 | public abstract bool GetAnchoredPreviewRectangleAt( PointerEventData eventData, out Rect rect ); 34 | 35 | public void Initialize( Panel panel ) 36 | { 37 | m_panel = panel; 38 | } 39 | 40 | public void SetActive( bool value ) 41 | { 42 | hoveredPointerId = PanelManager.NON_EXISTING_TOUCH; 43 | raycastZone.raycastTarget = value; 44 | } 45 | 46 | public void OnPointerEnter( PointerEventData eventData ) 47 | { 48 | if( PanelManager.Instance.AnchorPreviewPanelTo( this ) ) 49 | hoveredPointerId = eventData.pointerId; 50 | } 51 | 52 | // Saves the system from a complete shutdown in a rare case 53 | public void OnPointerDown( PointerEventData eventData ) 54 | { 55 | PanelManager.Instance.CancelDraggingPanel(); 56 | } 57 | 58 | public void OnPointerExit( PointerEventData eventData ) 59 | { 60 | if( eventData.pointerId == hoveredPointerId ) 61 | { 62 | hoveredPointerId = PanelManager.NON_EXISTING_TOUCH; 63 | PanelManager.Instance.StopAnchorPreviewPanelTo( this ); 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/AnchorZoneBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c1e9ad7f1e768884cbeef3db8ba62b20 3 | timeCreated: 1504697414 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/CanvasAnchorZone.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | 4 | namespace DynamicPanels 5 | { 6 | public class CanvasAnchorZone : AnchorZoneBase 7 | { 8 | private Direction direction; 9 | 10 | public void SetDirection( Direction direction ) 11 | { 12 | this.direction = direction; 13 | } 14 | 15 | public override bool Execute( PanelTab panelTab, PointerEventData eventData ) 16 | { 17 | Panel detachedPanel = PanelManager.Instance.DetachPanelTab( panelTab.Panel, panelTab.Panel.GetTabIndex( panelTab ) ); 18 | PanelManager.Instance.AnchorPanel( detachedPanel, m_panel.Canvas, direction ); 19 | 20 | return true; 21 | } 22 | 23 | public override bool GetAnchoredPreviewRectangleAt( PointerEventData eventData, out Rect rect ) 24 | { 25 | Vector2 size = m_panel.Canvas.Size; 26 | if( direction == Direction.Left ) 27 | rect = new Rect( 0f, 0f, size.x * 0.2f, size.y ); 28 | else if( direction == Direction.Top ) 29 | rect = new Rect( 0f, size.y * 0.8f, size.x, size.y * 0.2f ); 30 | else if( direction == Direction.Right ) 31 | rect = new Rect( size.x * 0.8f, 0f, size.x * 0.2f, size.y ); 32 | else 33 | rect = new Rect( 0f, 0f, size.x, size.y * 0.2f ); 34 | 35 | rect.position += ( rect.size - size ) * 0.5f; 36 | return true; 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/CanvasAnchorZone.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 73c0c2179033310488cd1644b36c1d76 3 | timeCreated: 1521654118 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/PanelAnchorZone.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | 4 | namespace DynamicPanels 5 | { 6 | public class PanelAnchorZone : AnchorZoneBase 7 | { 8 | public override bool Execute( PanelTab panelTab, PointerEventData eventData ) 9 | { 10 | Direction anchorDirection = GetAnchorDirection( eventData ); 11 | if( anchorDirection == Direction.None ) 12 | return false; 13 | 14 | Panel detachedPanel = PanelManager.Instance.DetachPanelTab( panelTab.Panel, panelTab.Panel.GetTabIndex( panelTab ) ); 15 | PanelManager.Instance.AnchorPanel( detachedPanel, m_panel, anchorDirection ); 16 | 17 | return true; 18 | } 19 | 20 | public override bool GetAnchoredPreviewRectangleAt( PointerEventData eventData, out Rect rect ) 21 | { 22 | Direction anchorDirection = GetAnchorDirection( eventData ); 23 | if( anchorDirection == Direction.None ) 24 | { 25 | rect = new Rect(); 26 | return false; 27 | } 28 | 29 | Vector2 size = m_panel.RectTransform.sizeDelta; 30 | size.y -= m_panel.Internal.HeaderHeight; 31 | 32 | float anchorWidth = Mathf.Min( m_panel.Canvas.PanelAnchorZoneLength, size.x * m_panel.Canvas.PanelAnchorZoneLengthRatio ); 33 | float anchorHeight = Mathf.Min( m_panel.Canvas.PanelAnchorZoneLength, size.y * m_panel.Canvas.PanelAnchorZoneLengthRatio ); 34 | 35 | if( anchorDirection == Direction.Left ) 36 | rect = new Rect( 0f, 0f, anchorWidth, size.y ); 37 | else if( anchorDirection == Direction.Top ) 38 | rect = new Rect( 0f, size.y - anchorHeight, size.x, anchorHeight ); 39 | else if( anchorDirection == Direction.Right ) 40 | rect = new Rect( size.x - anchorWidth, 0f, anchorWidth, size.y ); 41 | else 42 | rect = new Rect( 0f, 0f, size.x, anchorHeight ); 43 | 44 | rect.position += m_panel.RectTransform.anchoredPosition + ( rect.size - m_panel.Canvas.Size ) * 0.5f; 45 | return true; 46 | } 47 | 48 | private Direction GetAnchorDirection( PointerEventData eventData ) 49 | { 50 | Vector2 pointerPos; 51 | RectTransformUtility.ScreenPointToLocalPointInRectangle( m_panel.RectTransform, eventData.position, m_panel.Canvas.Internal.worldCamera, out pointerPos ); 52 | 53 | Vector2 size = m_panel.RectTransform.sizeDelta; 54 | size.y -= m_panel.Internal.HeaderHeight; 55 | 56 | float anchorWidth = Mathf.Min( m_panel.Canvas.PanelAnchorZoneLength, size.x * m_panel.Canvas.PanelAnchorZoneLengthRatio ); 57 | float anchorHeight = Mathf.Min( m_panel.Canvas.PanelAnchorZoneLength, size.y * m_panel.Canvas.PanelAnchorZoneLengthRatio ); 58 | 59 | if( pointerPos.y < anchorHeight ) 60 | return Direction.Bottom; 61 | if( pointerPos.y > size.y - anchorHeight ) 62 | return Direction.Top; 63 | if( pointerPos.x < anchorWidth ) 64 | return Direction.Left; 65 | if( pointerPos.x > size.x - anchorWidth ) 66 | return Direction.Right; 67 | 68 | return Direction.None; 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/PanelAnchorZone.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 004bce4254bbc924e91b36f9589ef1c6 3 | timeCreated: 1521654110 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/PanelHeaderAnchorZone.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | 4 | namespace DynamicPanels 5 | { 6 | public class PanelHeaderAnchorZone : AnchorZoneBase 7 | { 8 | public override bool Execute( PanelTab panelTab, PointerEventData eventData ) 9 | { 10 | Vector2 tabPreviewRect; 11 | int tabIndex = m_panel.Internal.GetTabIndexAt( eventData, out tabPreviewRect ); 12 | 13 | m_panel.AddTab( panelTab.Content, tabIndex ); 14 | return true; 15 | } 16 | 17 | public override bool GetAnchoredPreviewRectangleAt( PointerEventData eventData, out Rect rect ) 18 | { 19 | Vector2 tabPreviewRect; 20 | m_panel.Internal.GetTabIndexAt( eventData, out tabPreviewRect ); 21 | 22 | rect = new Rect( tabPreviewRect.x, m_panel.RectTransform.sizeDelta.y - m_panel.Internal.HeaderHeight, tabPreviewRect.y, m_panel.Internal.HeaderHeight ); 23 | rect.position += m_panel.RectTransform.anchoredPosition + ( rect.size - m_panel.Canvas.Size ) * 0.5f; 24 | 25 | return true; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Anchoring/PanelHeaderAnchorZone.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9add292c0bfe2e74990a6b9e339cc223 3 | timeCreated: 1521657390 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using UnityEngine.EventSystems; 4 | using UnityEngine.UI; 5 | 6 | #if UNITY_2017_3_OR_NEWER 7 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "DynamicPanels.Editor" )] 8 | #else 9 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "Assembly-CSharp-Editor" )] 10 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo( "Assembly-CSharp-Editor-firstpass" )] 11 | #endif 12 | namespace DynamicPanels 13 | { 14 | [DisallowMultipleComponent] 15 | public class DynamicPanelsCanvas : MonoBehaviour, IPointerEnterHandler, ISerializationCallbackReceiver 16 | { 17 | internal class InternalSettings 18 | { 19 | private readonly DynamicPanelsCanvas canvas; 20 | public readonly Camera worldCamera; 21 | 22 | public InternalSettings( DynamicPanelsCanvas canvas ) 23 | { 24 | this.canvas = canvas; 25 | 26 | #if UNITY_EDITOR 27 | if( !canvas.UnityCanvas ) // is null while inspecting this component in edit mode 28 | return; 29 | #endif 30 | 31 | if( canvas.UnityCanvas.renderMode == RenderMode.ScreenSpaceOverlay || 32 | ( canvas.UnityCanvas.renderMode == RenderMode.ScreenSpaceCamera && !canvas.UnityCanvas.worldCamera ) ) 33 | worldCamera = null; 34 | else 35 | worldCamera = canvas.UnityCanvas.worldCamera ? canvas.UnityCanvas.worldCamera : Camera.main; 36 | } 37 | 38 | public Panel DummyPanel { get { return canvas.dummyPanel; } } 39 | 40 | public List InitialPanelsUnanchored 41 | { 42 | get 43 | { 44 | if( canvas.initialPanelsUnanchored == null ) 45 | canvas.initialPanelsUnanchored = new List(); 46 | 47 | return canvas.initialPanelsUnanchored; 48 | } 49 | } 50 | 51 | public AnchoredPanelProperties InitialPanelsAnchored 52 | { 53 | get 54 | { 55 | if( canvas.initialPanelsAnchored == null ) 56 | canvas.initialPanelsAnchored = new AnchoredPanelProperties(); 57 | 58 | return canvas.initialPanelsAnchored; 59 | } 60 | } 61 | 62 | public bool IsLastDockedPanel( Panel panel ) 63 | { 64 | return panel.IsDocked && !PanelGroupHasAnyOtherPanels( canvas.RootPanelGroup, panel ); 65 | } 66 | 67 | private bool PanelGroupHasAnyOtherPanels( PanelGroup group, Panel panel ) 68 | { 69 | for( int i = 0; i < group.Count; i++ ) 70 | { 71 | if( group[i] is Panel ) 72 | { 73 | Panel _panel = (Panel) group[i]; 74 | if( _panel != panel && _panel != canvas.dummyPanel ) 75 | return true; 76 | } 77 | else if( PanelGroupHasAnyOtherPanels( (PanelGroup) group[i], panel ) ) 78 | return true; 79 | } 80 | 81 | return false; 82 | } 83 | 84 | public void OnApplicationQuit() 85 | { 86 | #if UNITY_2018_1_OR_NEWER 87 | canvas.OnApplicationQuitting(); 88 | #else 89 | canvas.OnApplicationQuit(); 90 | #endif 91 | } 92 | 93 | public void AnchorZonesSetActive( bool value ) { canvas.AnchorZonesSetActive( value ); } 94 | public void ReceiveRaycasts( bool value ) { canvas.background.raycastTarget = value; } 95 | } 96 | 97 | [System.Serializable] 98 | public class PanelProperties 99 | { 100 | public List tabs = new List(); 101 | } 102 | 103 | public class AnchoredPanelProperties 104 | { 105 | public PanelProperties panel = new PanelProperties(); 106 | public Direction anchorDirection; 107 | public Vector2 initialSize; 108 | 109 | public List subPanels = new List(); 110 | } 111 | 112 | // Credit: https://docs.unity3d.com/Manual/script-Serialization-Custom.html 113 | [System.Serializable] 114 | public struct SerializableAnchoredPanelProperties 115 | { 116 | public PanelProperties panel; 117 | public Direction anchorDirection; 118 | public Vector2 initialSize; 119 | 120 | public int childCount; 121 | public int indexOfFirstChild; 122 | } 123 | 124 | [System.Serializable] 125 | public class PanelTabProperties : ISerializationCallbackReceiver 126 | { 127 | public RectTransform content = null; 128 | public string id = null; 129 | public Vector2 minimumSize = new Vector2( 250f, 300f ); 130 | 131 | public string tabLabel = "Panel"; 132 | public Sprite tabIcon = null; 133 | 134 | void ISerializationCallbackReceiver.OnBeforeSerialize() 135 | { 136 | if( string.IsNullOrEmpty( id ) ) 137 | id = System.Guid.NewGuid().ToString(); 138 | } 139 | 140 | void ISerializationCallbackReceiver.OnAfterDeserialize() 141 | { 142 | } 143 | } 144 | 145 | public RectTransform RectTransform { get; private set; } 146 | public Canvas UnityCanvas { get; private set; } 147 | 148 | #if UNITY_EDITOR 149 | private InternalSettings m_internal; 150 | internal InternalSettings Internal 151 | { 152 | get 153 | { 154 | if( m_internal == null ) 155 | m_internal = new InternalSettings( this ); 156 | 157 | return m_internal; 158 | } 159 | } 160 | #else 161 | internal InternalSettings Internal { get; private set; } 162 | #endif 163 | 164 | [SerializeField] 165 | [HideInInspector] 166 | private string m_id; 167 | public string ID 168 | { 169 | get { return m_id; } 170 | set { m_id = value; } 171 | } 172 | 173 | public UnanchoredPanelGroup UnanchoredPanelGroup { get; private set; } 174 | public PanelGroup RootPanelGroup { get; private set; } 175 | 176 | public Vector2 Size { get; private set; } 177 | 178 | private Panel dummyPanel; 179 | private Graphic background; 180 | 181 | private RectTransform anchorZonesParent; 182 | private readonly CanvasAnchorZone[] anchorZones = new CanvasAnchorZone[4]; // one for each side 183 | 184 | #pragma warning disable 0649 185 | [SerializeField] 186 | private bool m_leaveFreeSpace = true; 187 | public bool LeaveFreeSpace 188 | { 189 | get { return m_leaveFreeSpace; } 190 | set 191 | { 192 | m_leaveFreeSpace = value; 193 | if( !m_leaveFreeSpace ) 194 | dummyPanel.Detach(); 195 | else if( !dummyPanel.IsDocked ) 196 | { 197 | // Add the free space to the middle 198 | if( RootPanelGroup.Count <= 1 ) 199 | RootPanelGroup.AddElement( dummyPanel ); 200 | else 201 | RootPanelGroup.AddElementBefore( RootPanelGroup[RootPanelGroup.Count / 2], dummyPanel ); 202 | } 203 | } 204 | } 205 | 206 | [SerializeField] 207 | private Vector2 minimumFreeSpace = new Vector2( 50f, 50f ); 208 | 209 | [SerializeField] 210 | private RectTransform freeSpaceTargetTransform; 211 | private Vector2 freeSpacePrevPos, freeSpacePrevSize; 212 | 213 | public bool PreventDetachingLastDockedPanel; 214 | 215 | [SerializeField] 216 | private float m_panelResizableAreaLength = 12f; 217 | public float PanelResizableAreaLength { get { return m_panelResizableAreaLength; } } 218 | 219 | [SerializeField] 220 | private float m_canvasAnchorZoneLength = 20f; 221 | public float CanvasAnchorZoneLength { get { return m_canvasAnchorZoneLength; } } 222 | 223 | [SerializeField] 224 | private float m_panelAnchorZoneLength = 100f; 225 | public float PanelAnchorZoneLength { get { return m_panelAnchorZoneLength; } } 226 | 227 | private const float m_panelAnchorZoneLengthRatio = 0.31f; 228 | public float PanelAnchorZoneLengthRatio { get { return m_panelAnchorZoneLengthRatio; } } 229 | 230 | [SerializeField] 231 | private List initialPanelsUnanchored; 232 | 233 | [SerializeField] 234 | [HideInInspector] 235 | private List initialPanelsAnchoredSerialized; 236 | private AnchoredPanelProperties initialPanelsAnchored; 237 | #pragma warning restore 0649 238 | 239 | private bool updateBounds = true; 240 | private bool isDirty = false; 241 | 242 | private bool isQuitting = false; 243 | 244 | private void Awake() 245 | { 246 | RectTransform = (RectTransform) transform; 247 | UnityCanvas = GetComponentInParent(); 248 | #if !UNITY_EDITOR 249 | Internal = new InternalSettings( this ); 250 | #endif 251 | 252 | UnanchoredPanelGroup = new UnanchoredPanelGroup( this ); 253 | RectTransform.ChangePivotWithoutAffectingPosition( new Vector2( 0.5f, 0.5f ) ); 254 | 255 | if( !GetComponent() ) 256 | gameObject.AddComponent(); 257 | 258 | Size = RectTransform.rect.size; 259 | 260 | InitializeRootGroup(); 261 | InitializeAnchorZones(); 262 | 263 | background = GetComponent(); 264 | if( !background ) 265 | { 266 | background = gameObject.AddComponent(); 267 | background.raycastTarget = false; 268 | } 269 | 270 | PanelManager.Instance.RegisterCanvas( this ); 271 | 272 | #if UNITY_2018_1_OR_NEWER 273 | // OnApplicationQuit isn't reliable on some Unity versions when Application.wantsToQuit is used; Application.quitting is the only reliable solution on those versions 274 | // https://issuetracker.unity3d.com/issues/onapplicationquit-method-is-called-before-application-dot-wantstoquit-event-is-raised 275 | Application.quitting -= OnApplicationQuitting; 276 | Application.quitting += OnApplicationQuitting; 277 | #endif 278 | } 279 | 280 | private void Start() 281 | { 282 | Size = RectTransform.rect.size; 283 | 284 | HashSet createdTabs = new HashSet(); // A set to prevent duplicate tabs or to prevent making canvas itself a panel 285 | Transform tr = transform; 286 | while( tr ) 287 | { 288 | createdTabs.Add( tr ); 289 | tr = tr.parent; 290 | } 291 | 292 | Dictionary initialSizes = null; 293 | if( initialPanelsAnchored != null ) 294 | { 295 | initialSizes = new Dictionary( initialPanelsAnchoredSerialized.Count ); 296 | CreateAnchoredPanelsRecursively( initialPanelsAnchored.subPanels, dummyPanel, createdTabs, initialSizes ); 297 | } 298 | 299 | for( int i = 0; i < initialPanelsUnanchored.Count; i++ ) 300 | CreateInitialPanel( initialPanelsUnanchored[i], null, Direction.None, createdTabs ); 301 | 302 | initialPanelsUnanchored = null; 303 | initialPanelsAnchored = null; 304 | initialPanelsAnchoredSerialized = null; 305 | 306 | if( freeSpaceTargetTransform ) 307 | { 308 | if( freeSpaceTargetTransform.parent != RectTransform ) 309 | freeSpaceTargetTransform.SetParent( RectTransform, false ); 310 | 311 | freeSpaceTargetTransform.anchorMin = Vector2.zero; 312 | freeSpaceTargetTransform.anchorMax = Vector2.zero; 313 | freeSpaceTargetTransform.pivot = Vector2.zero; 314 | freeSpaceTargetTransform.SetAsFirstSibling(); 315 | } 316 | 317 | LeaveFreeSpace = m_leaveFreeSpace; 318 | LateUpdate(); // Update layout 319 | 320 | if( m_leaveFreeSpace ) 321 | { 322 | // Minimize all panels to their minimum size 323 | dummyPanel.ResizeTo( new Vector2( 99999f, 99999f ) ); 324 | 325 | //RootPanelGroup.Internal.TryChangeSizeOf( dummyPanel, Direction.Left, 20009f ); 326 | //RootPanelGroup.Internal.TryChangeSizeOf( dummyPanel, Direction.Top, 20009f ); // Magick number.. 327 | //RootPanelGroup.Internal.TryChangeSizeOf( dummyPanel, Direction.Right, 20009f ); // or not? 328 | //RootPanelGroup.Internal.TryChangeSizeOf( dummyPanel, Direction.Bottom, 20009f ); // A: just a big random number U_U 329 | } 330 | 331 | if( initialSizes != null ) 332 | ResizeAnchoredPanelsRecursively( RootPanelGroup, initialSizes ); 333 | } 334 | 335 | private void OnDestroy() 336 | { 337 | #if UNITY_2018_1_OR_NEWER 338 | Application.quitting -= OnApplicationQuitting; 339 | #endif 340 | 341 | if( !isQuitting ) 342 | PanelManager.Instance.UnregisterCanvas( this ); 343 | } 344 | 345 | #if UNITY_2018_1_OR_NEWER 346 | private void OnApplicationQuitting() 347 | #else 348 | private void OnApplicationQuit() 349 | #endif 350 | { 351 | isQuitting = true; 352 | } 353 | 354 | private void LateUpdate() 355 | { 356 | if( isDirty ) 357 | { 358 | PanelManager.Instance.StopCanvasOperations( this ); 359 | 360 | RootPanelGroup.Internal.UpdateLayout(); 361 | UnanchoredPanelGroup.Internal.UpdateLayout(); 362 | 363 | RootPanelGroup.Internal.UpdateSurroundings( null, null, null, null ); 364 | } 365 | 366 | if( updateBounds ) 367 | { 368 | UpdateBounds(); 369 | updateBounds = false; 370 | } 371 | 372 | if( isDirty ) 373 | { 374 | RootPanelGroup.Internal.EnsureMinimumSize(); 375 | UnanchoredPanelGroup.Internal.EnsureMinimumSize(); 376 | 377 | isDirty = false; 378 | } 379 | 380 | if( m_leaveFreeSpace && freeSpaceTargetTransform ) 381 | { 382 | Vector2 freeSpacePos = dummyPanel.Position; 383 | Vector2 freeSpaceSize = dummyPanel.Size; 384 | if( freeSpacePos != freeSpacePrevPos || freeSpaceSize != freeSpacePrevSize ) 385 | { 386 | freeSpacePrevPos = freeSpacePos; 387 | freeSpacePrevSize = freeSpaceSize; 388 | 389 | freeSpaceTargetTransform.anchoredPosition = freeSpacePos; 390 | freeSpaceTargetTransform.sizeDelta = freeSpaceSize; 391 | } 392 | } 393 | } 394 | 395 | public void SetDirty() 396 | { 397 | isDirty = true; 398 | updateBounds = true; 399 | } 400 | 401 | public void ForceRebuildLayoutImmediate() 402 | { 403 | LateUpdate(); 404 | } 405 | 406 | void IPointerEnterHandler.OnPointerEnter( PointerEventData eventData ) 407 | { 408 | PanelManager.Instance.OnPointerEnteredCanvas( this, eventData ); 409 | } 410 | 411 | private void OnRectTransformDimensionsChange() 412 | { 413 | updateBounds = true; 414 | } 415 | 416 | private void UpdateBounds() 417 | { 418 | Size = RectTransform.rect.size; 419 | 420 | RootPanelGroup.Internal.UpdateBounds( Vector2.zero, Size ); 421 | UnanchoredPanelGroup.Internal.UpdateBounds( Vector2.zero, Size ); 422 | } 423 | 424 | private void CreateAnchoredPanelsRecursively( List anchoredPanels, Panel rootPanel, HashSet createdTabs, Dictionary initialSizes ) 425 | { 426 | if( anchoredPanels == null ) 427 | return; 428 | 429 | for( int i = 0; i < anchoredPanels.Count; i++ ) 430 | { 431 | Panel panel = CreateInitialPanel( anchoredPanels[i].panel, rootPanel, anchoredPanels[i].anchorDirection, createdTabs ); 432 | if( panel == null ) 433 | panel = rootPanel; 434 | else if( anchoredPanels[i].initialSize != Vector2.zero ) 435 | initialSizes[panel] = anchoredPanels[i].initialSize; 436 | 437 | CreateAnchoredPanelsRecursively( anchoredPanels[i].subPanels, panel, createdTabs, initialSizes ); 438 | } 439 | } 440 | 441 | private void ResizeAnchoredPanelsRecursively( PanelGroup group, Dictionary initialSizes ) 442 | { 443 | if( group == null ) 444 | return; 445 | 446 | int count = group.Count; 447 | for( int i = 0; i < count; i++ ) 448 | { 449 | Panel panel = group[i] as Panel; 450 | if( panel != null ) 451 | { 452 | Vector2 initialSize; 453 | if( initialSizes.TryGetValue( panel, out initialSize ) ) 454 | panel.ResizeTo( initialSize, Direction.Right, Direction.Top ); 455 | } 456 | else 457 | ResizeAnchoredPanelsRecursively( group[i] as PanelGroup, initialSizes ); 458 | } 459 | } 460 | 461 | private Panel CreateInitialPanel( PanelProperties properties, Panel anchor, Direction anchorDirection, HashSet createdTabs ) 462 | { 463 | Panel panel = null; 464 | for( int i = 0; i < properties.tabs.Count; i++ ) 465 | { 466 | PanelTabProperties panelProps = properties.tabs[i]; 467 | if( panelProps.content ) 468 | { 469 | if( createdTabs.Contains( panelProps.content ) ) 470 | continue; 471 | 472 | if( panelProps.content.parent != RectTransform ) 473 | panelProps.content.SetParent( RectTransform, false ); 474 | 475 | PanelTab tab; 476 | if( panel == null ) 477 | { 478 | panel = PanelUtils.CreatePanelFor( panelProps.content, this ); 479 | tab = panel[0]; 480 | } 481 | else 482 | tab = panel.AddTab( panelProps.content ); 483 | 484 | tab.Icon = panelProps.tabIcon; 485 | tab.Label = panelProps.tabLabel; 486 | tab.MinSize = panelProps.minimumSize; 487 | tab.ID = panelProps.id; 488 | 489 | createdTabs.Add( panelProps.content ); 490 | } 491 | } 492 | 493 | if( panel != null ) 494 | { 495 | panel.ActiveTab = 0; 496 | 497 | if( anchor != null && anchorDirection != Direction.None ) 498 | panel.DockToPanel( anchor, anchorDirection ); 499 | } 500 | 501 | return panel; 502 | } 503 | 504 | private void InitializeRootGroup() 505 | { 506 | dummyPanel = PanelUtils.Internal.CreatePanel( null, this ); 507 | dummyPanel.gameObject.name = "DummyPanel"; 508 | dummyPanel.CanvasGroup.alpha = 0f; 509 | dummyPanel.Internal.SetDummy( minimumFreeSpace ); 510 | 511 | RootPanelGroup = new PanelGroup( this, Direction.Right ); 512 | RootPanelGroup.AddElement( dummyPanel ); 513 | } 514 | 515 | private void InitializeAnchorZones() 516 | { 517 | anchorZonesParent = (RectTransform) new GameObject( "CanvasAnchorZone", typeof( RectTransform ) ).transform; 518 | anchorZonesParent.SetParent( RectTransform, false ); 519 | anchorZonesParent.anchorMin = Vector2.zero; 520 | anchorZonesParent.anchorMax = Vector2.one; 521 | anchorZonesParent.sizeDelta = Vector2.zero; 522 | 523 | CreateAnchorZone( Direction.Left, new Vector2( 0f, 0f ), new Vector2( 0f, 1f ), new Vector2( m_canvasAnchorZoneLength, 0f ) ); 524 | CreateAnchorZone( Direction.Top, new Vector2( 0f, 1f ), new Vector2( 1f, 1f ), new Vector2( 0f, m_canvasAnchorZoneLength ) ); 525 | CreateAnchorZone( Direction.Right, new Vector2( 1f, 0f ), new Vector2( 1f, 1f ), new Vector2( m_canvasAnchorZoneLength, 0f ) ); 526 | CreateAnchorZone( Direction.Bottom, new Vector2( 0f, 0f ), new Vector2( 1f, 0f ), new Vector2( 0f, m_canvasAnchorZoneLength ) ); 527 | 528 | for( int i = 0; i < anchorZones.Length; i++ ) 529 | anchorZones[i].SetActive( false ); 530 | } 531 | 532 | private void CreateAnchorZone( Direction direction, Vector2 anchorMin, Vector2 anchorMax, Vector2 sizeDelta ) 533 | { 534 | CanvasAnchorZone anchorZone = new GameObject( "AnchorZone" + direction, typeof( RectTransform ) ).AddComponent(); 535 | anchorZone.Initialize( dummyPanel ); 536 | anchorZone.SetDirection( direction ); 537 | 538 | anchorZone.RectTransform.SetParent( anchorZonesParent, false ); 539 | 540 | anchorZone.RectTransform.pivot = anchorMin; 541 | anchorZone.RectTransform.anchorMin = anchorMin; 542 | anchorZone.RectTransform.anchorMax = anchorMax; 543 | anchorZone.RectTransform.anchoredPosition = Vector2.zero; 544 | anchorZone.RectTransform.sizeDelta = sizeDelta; 545 | 546 | anchorZones[(int) direction] = anchorZone; 547 | } 548 | 549 | private void AnchorZonesSetActive( bool value ) 550 | { 551 | if( !enabled ) 552 | return; 553 | 554 | if( value ) 555 | anchorZonesParent.SetAsLastSibling(); 556 | 557 | for( int i = 0; i < anchorZones.Length; i++ ) 558 | anchorZones[i].SetActive( value ); 559 | } 560 | 561 | [ContextMenu( "Save Layout" )] 562 | public void SaveLayout() 563 | { 564 | PanelSerialization.SerializeCanvas( this ); 565 | } 566 | 567 | [ContextMenu( "Load Layout" )] 568 | public void LoadLayout() 569 | { 570 | PanelSerialization.DeserializeCanvas( this ); 571 | } 572 | 573 | void ISerializationCallbackReceiver.OnBeforeSerialize() 574 | { 575 | if( initialPanelsAnchoredSerialized == null ) 576 | initialPanelsAnchoredSerialized = new List(); 577 | else 578 | initialPanelsAnchoredSerialized.Clear(); 579 | 580 | if( initialPanelsAnchored == null ) 581 | initialPanelsAnchored = new AnchoredPanelProperties(); 582 | 583 | if( string.IsNullOrEmpty( m_id ) ) 584 | m_id = System.Guid.NewGuid().ToString(); 585 | 586 | AddToSerializedAnchoredPanelProperties( initialPanelsAnchored ); 587 | } 588 | 589 | void ISerializationCallbackReceiver.OnAfterDeserialize() 590 | { 591 | if( initialPanelsAnchoredSerialized != null && initialPanelsAnchoredSerialized.Count > 0 ) 592 | ReadFromSerializedAnchoredPanelProperties( 0, out initialPanelsAnchored ); 593 | else 594 | initialPanelsAnchored = new AnchoredPanelProperties(); 595 | } 596 | 597 | private void AddToSerializedAnchoredPanelProperties( AnchoredPanelProperties props ) 598 | { 599 | SerializableAnchoredPanelProperties serializedProps = new SerializableAnchoredPanelProperties() 600 | { 601 | panel = props.panel, 602 | anchorDirection = props.anchorDirection, 603 | initialSize = props.initialSize, 604 | childCount = props.subPanels.Count, 605 | indexOfFirstChild = initialPanelsAnchoredSerialized.Count + 1 606 | }; 607 | 608 | initialPanelsAnchoredSerialized.Add( serializedProps ); 609 | for( int i = 0; i < props.subPanels.Count; i++ ) 610 | AddToSerializedAnchoredPanelProperties( props.subPanels[i] ); 611 | } 612 | 613 | private int ReadFromSerializedAnchoredPanelProperties( int index, out AnchoredPanelProperties props ) 614 | { 615 | SerializableAnchoredPanelProperties serializedProps = initialPanelsAnchoredSerialized[index]; 616 | AnchoredPanelProperties newProps = new AnchoredPanelProperties() 617 | { 618 | panel = serializedProps.panel, 619 | anchorDirection = serializedProps.anchorDirection, 620 | initialSize = serializedProps.initialSize, 621 | subPanels = new List() 622 | }; 623 | 624 | for( int i = 0; i != serializedProps.childCount; i++ ) 625 | { 626 | AnchoredPanelProperties childProps; 627 | index = ReadFromSerializedAnchoredPanelProperties( ++index, out childProps ); 628 | newProps.subPanels.Add( childProps ); 629 | } 630 | 631 | props = newProps; 632 | return index; 633 | } 634 | } 635 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e09a4b7ae29894a4194f95800d897bb0 3 | timeCreated: 1520957458 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: -75 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d53847df923c5a24bb696de6d2d72572 3 | folderAsset: yes 4 | timeCreated: 1507479845 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping/IPanelGroupElement.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace DynamicPanels 4 | { 5 | public interface IPanelGroupElement 6 | { 7 | DynamicPanelsCanvas Canvas { get; } 8 | PanelGroup Group { get; } 9 | 10 | Vector2 Position { get; } 11 | Vector2 Size { get; } 12 | Vector2 MinSize { get; } 13 | 14 | void ResizeTo( Vector2 newSize, Direction horizontalDir = Direction.Right, Direction verticalDir = Direction.Bottom ); 15 | 16 | void DockToRoot( Direction direction ); 17 | void DockToPanel( IPanelGroupElement anchor, Direction direction ); 18 | 19 | IPanelGroupElement GetSurroundingElement( Direction direction ); 20 | } 21 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping/IPanelGroupElement.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 836ab53589e33744cb3abe654e6b46f8 3 | timeCreated: 1504794445 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping/PanelGroup.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace DynamicPanels 5 | { 6 | public class PanelGroup : IPanelGroupElement 7 | { 8 | internal class InternalSettings 9 | { 10 | private readonly PanelGroup group; 11 | 12 | public InternalSettings( PanelGroup group ) { this.group = group; } 13 | 14 | public void SetDirty() { group.SetDirty(); } 15 | public void UpdateBounds( Vector2 position, Vector2 size ) { group.UpdateBounds( position, size ); } 16 | public void UpdateLayout() { group.UpdateLayout(); } 17 | public void UpdateSurroundings( IPanelGroupElement left, IPanelGroupElement top, IPanelGroupElement right, IPanelGroupElement bottom ) { group.UpdateSurroundings( left, top, right, bottom ); } 18 | public void TryChangeSizeOf( IPanelGroupElement element, Direction direction, float deltaSize ) { group.TryChangeSizeOf( element, direction, deltaSize ); } 19 | public void ResizeElementTo( IPanelGroupElement element, Vector2 newSize, Direction horizontalDir, Direction verticalDir ) { group.ResizeElementTo( element, newSize, horizontalDir, verticalDir ); } 20 | public void ReplaceElement( IPanelGroupElement beforeElement, IPanelGroupElement afterElement ) { group.ReplaceElement( beforeElement, afterElement ); } 21 | 22 | public void EnsureMinimumSize() 23 | { 24 | for( int i = 0; i < group.elements.Count; i++ ) 25 | group.EnsureMinimumSizeOf( group.elements[i] ); 26 | } 27 | } 28 | 29 | private class ElementDirtyProperties 30 | { 31 | public IPanelGroupElement element; 32 | public float posX, posY, sizeX, sizeY; 33 | 34 | public ElementDirtyProperties() { } 35 | public ElementDirtyProperties( IPanelGroupElement element ) { this.element = element; } 36 | 37 | public void Reset( IPanelGroupElement element ) 38 | { 39 | this.element = element; 40 | posX = posY = sizeX = sizeY = 0f; 41 | } 42 | } 43 | 44 | protected const float MIN_SIZE_TOLERANCE = 1E-4f; 45 | 46 | protected readonly Direction direction; 47 | protected readonly List elements; 48 | 49 | protected readonly IPanelGroupElement[] surroundings; 50 | 51 | public DynamicPanelsCanvas Canvas { get; private set; } 52 | public PanelGroup Group { get; protected set; } 53 | 54 | internal InternalSettings Internal { get; private set; } 55 | 56 | public Vector2 Position { get; protected set; } 57 | public Vector2 Size { get; protected set; } 58 | public Vector2 MinSize { get; protected set; } 59 | 60 | private List resizeProperties; 61 | private int resizePropsIndex; 62 | 63 | protected bool isDirty = false; 64 | 65 | public int Count { get { return elements.Count; } } 66 | public IPanelGroupElement this[int index] { get { return elements[index]; } } 67 | 68 | public PanelGroup( DynamicPanelsCanvas canvas, Direction direction ) 69 | { 70 | Canvas = canvas; 71 | Internal = new InternalSettings( this ); 72 | 73 | this.direction = direction; 74 | 75 | elements = new List( 2 ); 76 | surroundings = new IPanelGroupElement[4]; 77 | } 78 | 79 | public bool IsInSameDirection( Direction direction ) 80 | { 81 | if( direction == Direction.None ) 82 | return false; 83 | 84 | if( direction == Direction.Left || direction == Direction.Right ) 85 | return this.direction == Direction.Left || this.direction == Direction.Right; 86 | 87 | return this.direction == Direction.Top || this.direction == Direction.Bottom; 88 | } 89 | 90 | public IPanelGroupElement GetSurroundingElement( Direction direction ) 91 | { 92 | return surroundings[(int) direction]; 93 | } 94 | 95 | protected void SetDirty() 96 | { 97 | isDirty = true; 98 | 99 | PanelGroup parentGroup = Group; 100 | while( parentGroup != null ) 101 | { 102 | parentGroup.isDirty = true; 103 | parentGroup = parentGroup.Group; 104 | } 105 | 106 | Canvas.SetDirty(); 107 | } 108 | 109 | protected virtual void UpdateBounds( Vector2 position, Vector2 size ) 110 | { 111 | Position = position; 112 | 113 | if( elements.Count == 1 ) 114 | UpdateBoundsOf( elements[0], position, size ); 115 | else 116 | { 117 | float multiplier; 118 | bool horizontal = IsInSameDirection( Direction.Right ); 119 | if( horizontal ) 120 | { 121 | if( Size.x == 0f ) 122 | multiplier = size.x; 123 | else 124 | multiplier = size.x / Size.x; 125 | } 126 | else 127 | { 128 | if( Size.y == 0f ) 129 | multiplier = size.y; 130 | else 131 | multiplier = size.y / Size.y; 132 | } 133 | 134 | for( int i = 0; i < elements.Count; i++ ) 135 | { 136 | Vector2 elementSize = elements[i].Size; 137 | 138 | if( horizontal ) 139 | { 140 | elementSize.x *= multiplier; 141 | elementSize.y = size.y; 142 | 143 | UpdateBoundsOf( elements[i], position, elementSize ); 144 | position.x += elementSize.x; 145 | } 146 | else 147 | { 148 | elementSize.x = size.x; 149 | elementSize.y *= multiplier; 150 | 151 | UpdateBoundsOf( elements[i], position, elementSize ); 152 | position.y += elementSize.y; 153 | } 154 | } 155 | } 156 | 157 | Size = size; 158 | } 159 | 160 | protected virtual void UpdateLayout() 161 | { 162 | if( isDirty ) 163 | { 164 | elements.RemoveAll( ( element ) => element.IsNull() || element.Group != this ); 165 | 166 | for( int i = elements.Count - 1; i >= 0; i-- ) 167 | { 168 | PanelGroup subGroup = elements[i] as PanelGroup; 169 | if( subGroup != null ) 170 | { 171 | subGroup.UpdateLayout(); 172 | 173 | int count = subGroup.Count; 174 | if( count == 0 ) 175 | elements.RemoveAt( i ); 176 | else if( count == 1 ) 177 | { 178 | elements[i] = subGroup.elements[0]; 179 | SetGroupFor( elements[i], this ); 180 | i++; 181 | } 182 | else if( subGroup.IsInSameDirection( direction ) ) 183 | { 184 | elements.RemoveAt( i ); 185 | elements.InsertRange( i, subGroup.elements ); 186 | for( int j = 0; j < count; j++, i++ ) 187 | SetGroupFor( elements[i], this ); 188 | } 189 | } 190 | } 191 | 192 | Vector2 size = Vector2.zero; 193 | Vector2 minSize = Vector2.zero; 194 | bool horizontal = IsInSameDirection( Direction.Right ); 195 | int dummyPanelIndex = -1; 196 | for( int i = 0; i < elements.Count; i++ ) 197 | { 198 | Vector2 elementSize = elements[i].Size; 199 | Vector2 elementMinSize = elements[i].MinSize; 200 | 201 | // Rescue elements whose sizes are stuck at 0 202 | bool rescueElement = false; 203 | if( elementSize.x == 0f && elementMinSize.x > 0f ) 204 | { 205 | elementSize.x = Mathf.Min( 1f, elementMinSize.x ); 206 | rescueElement = true; 207 | } 208 | if( elementSize.y == 0f && elementMinSize.y > 0f ) 209 | { 210 | elementSize.y = Mathf.Min( 1f, elementMinSize.y ); 211 | rescueElement = true; 212 | } 213 | 214 | if( rescueElement ) 215 | UpdateBoundsOf( elements[i], elements[i].Position, elementSize ); 216 | 217 | if( i == 0 ) 218 | { 219 | size = elementSize; 220 | minSize = elementMinSize; 221 | } 222 | else 223 | { 224 | if( horizontal ) 225 | { 226 | size.x += elementSize.x; 227 | minSize.x += elementMinSize.x; 228 | 229 | if( elementSize.y < size.y ) 230 | size.y = elementSize.y; 231 | 232 | if( elementMinSize.y > minSize.y ) 233 | minSize.y = elementMinSize.y; 234 | } 235 | else 236 | { 237 | size.y += elementSize.y; 238 | minSize.y += elementMinSize.y; 239 | 240 | if( elementSize.x < size.x ) 241 | size.x = elementSize.x; 242 | 243 | if( elementMinSize.x > minSize.x ) 244 | minSize.x = elementMinSize.x; 245 | } 246 | } 247 | 248 | if( elements[i] is Panel && ( (Panel) elements[i] ).Internal.IsDummy ) 249 | dummyPanelIndex = i; 250 | } 251 | 252 | if( dummyPanelIndex >= 0 ) 253 | { 254 | Vector2 flexibleSpace = Vector2.zero; 255 | if( size.x < Size.x ) 256 | { 257 | flexibleSpace.x = Size.x - size.x; 258 | size.x = Size.x; 259 | } 260 | 261 | if( size.y < Size.y ) 262 | { 263 | flexibleSpace.y = Size.y - size.y; 264 | size.y = Size.y; 265 | } 266 | 267 | ( (Panel) elements[dummyPanelIndex] ).RectTransform.sizeDelta += flexibleSpace; 268 | } 269 | 270 | Size = size; 271 | MinSize = minSize; 272 | 273 | isDirty = false; 274 | } 275 | } 276 | 277 | protected void UpdateSurroundings( IPanelGroupElement left, IPanelGroupElement top, IPanelGroupElement right, IPanelGroupElement bottom ) 278 | { 279 | surroundings[(int) Direction.Left] = left; 280 | surroundings[(int) Direction.Top] = top; 281 | surroundings[(int) Direction.Right] = right; 282 | surroundings[(int) Direction.Bottom] = bottom; 283 | 284 | bool horizontal = IsInSameDirection( Direction.Right ); 285 | for( int i = 0; i < elements.Count; i++ ) 286 | { 287 | if( horizontal ) 288 | { 289 | left = i > 0 ? elements[i - 1] : surroundings[(int) Direction.Left]; 290 | right = i < elements.Count - 1 ? elements[i + 1] : surroundings[(int) Direction.Right]; 291 | } 292 | else 293 | { 294 | bottom = i > 0 ? elements[i - 1] : surroundings[(int) Direction.Bottom]; 295 | top = i < elements.Count - 1 ? elements[i + 1] : surroundings[(int) Direction.Top]; 296 | } 297 | 298 | PanelGroup subGroup = elements[i] as PanelGroup; 299 | if( subGroup != null ) 300 | subGroup.UpdateSurroundings( left, top, right, bottom ); 301 | else 302 | ( (Panel) elements[i] ).Internal.UpdateSurroundings( left, top, right, bottom ); 303 | } 304 | } 305 | 306 | protected void ResizeElementTo( IPanelGroupElement element, Vector2 newSize, Direction horizontalDir, Direction verticalDir ) 307 | { 308 | if( horizontalDir != Direction.Left && horizontalDir != Direction.Right ) 309 | horizontalDir = Direction.Right; 310 | if( verticalDir != Direction.Bottom && verticalDir != Direction.Top ) 311 | verticalDir = Direction.Bottom; 312 | 313 | Direction horizontalOpposite = horizontalDir.Opposite(); 314 | Direction verticalOpposite = verticalDir.Opposite(); 315 | 316 | float flexibleWidth = newSize.x - element.Size.x; 317 | if( flexibleWidth > MIN_SIZE_TOLERANCE ) 318 | { 319 | TryChangeSizeOf( element, horizontalDir, flexibleWidth ); 320 | 321 | flexibleWidth = newSize.x - element.Size.x; 322 | if( flexibleWidth > MIN_SIZE_TOLERANCE ) 323 | TryChangeSizeOf( element, horizontalOpposite, flexibleWidth ); 324 | } 325 | else if( flexibleWidth < -MIN_SIZE_TOLERANCE ) 326 | { 327 | TryChangeSizeOf( element.GetSurroundingElement( horizontalDir ), horizontalOpposite, -flexibleWidth ); 328 | 329 | flexibleWidth = newSize.x - element.Size.x; 330 | if( flexibleWidth < -MIN_SIZE_TOLERANCE ) 331 | TryChangeSizeOf( element.GetSurroundingElement( horizontalOpposite ), horizontalDir, -flexibleWidth ); 332 | } 333 | 334 | float flexibleHeight = newSize.y - element.Size.y; 335 | if( flexibleHeight > MIN_SIZE_TOLERANCE ) 336 | { 337 | TryChangeSizeOf( element, verticalDir, flexibleHeight ); 338 | 339 | flexibleHeight = newSize.y - element.Size.y; 340 | if( flexibleHeight > MIN_SIZE_TOLERANCE ) 341 | TryChangeSizeOf( element, verticalOpposite, flexibleHeight ); 342 | } 343 | else if( flexibleHeight < -MIN_SIZE_TOLERANCE ) 344 | { 345 | TryChangeSizeOf( element.GetSurroundingElement( verticalDir ), verticalOpposite, -flexibleHeight ); 346 | 347 | flexibleHeight = newSize.y - element.Size.y; 348 | if( flexibleHeight < -MIN_SIZE_TOLERANCE ) 349 | TryChangeSizeOf( element.GetSurroundingElement( verticalOpposite ), verticalDir, -flexibleHeight ); 350 | } 351 | } 352 | 353 | protected virtual void EnsureMinimumSizeOf( IPanelGroupElement element ) 354 | { 355 | float flexibleWidth = element.Size.x - element.MinSize.x; 356 | if( flexibleWidth < -MIN_SIZE_TOLERANCE ) 357 | { 358 | TryChangeSizeOf( element, Direction.Right, -flexibleWidth ); 359 | 360 | flexibleWidth = element.Size.x - element.MinSize.x; 361 | if( flexibleWidth < -MIN_SIZE_TOLERANCE ) 362 | TryChangeSizeOf( element, Direction.Left, -flexibleWidth ); 363 | } 364 | 365 | float flexibleHeight = element.Size.y - element.MinSize.y; 366 | if( flexibleHeight < -MIN_SIZE_TOLERANCE ) 367 | { 368 | TryChangeSizeOf( element, Direction.Bottom, -flexibleHeight ); 369 | 370 | flexibleHeight = element.Size.y - element.MinSize.y; 371 | if( flexibleHeight < -MIN_SIZE_TOLERANCE ) 372 | TryChangeSizeOf( element, Direction.Top, -flexibleHeight ); 373 | } 374 | 375 | PanelGroup subGroup = element as PanelGroup; 376 | if( subGroup != null ) 377 | subGroup.Internal.EnsureMinimumSize(); 378 | } 379 | 380 | protected void TryChangeSizeOf( IPanelGroupElement element, Direction direction, float deltaSize ) 381 | { 382 | if( element.IsNull() || deltaSize <= MIN_SIZE_TOLERANCE || element.GetSurroundingElement( direction ).IsNull() ) 383 | return; 384 | 385 | resizePropsIndex = 0; 386 | 387 | IPanelGroupElement surroundingElement = element.GetSurroundingElement( direction ); 388 | element = surroundingElement.GetSurroundingElement( direction.Opposite() ); 389 | AddResizeProperty( element ); 390 | 391 | float deltaMovement = TryChangeSizeOfInternal( surroundingElement, direction, deltaSize ); 392 | if( resizePropsIndex > 1 ) 393 | { 394 | ResizeElementHelper( 0, direction, deltaMovement ); 395 | 396 | for( int i = 0; i < resizePropsIndex; i++ ) 397 | { 398 | ElementDirtyProperties properties = resizeProperties[i]; 399 | 400 | Vector2 position = properties.element.Position + new Vector2( properties.posX, properties.posY ); 401 | Vector2 size = properties.element.Size + new Vector2( properties.sizeX, properties.sizeY ); 402 | 403 | UpdateBoundsOf( properties.element, position, size ); 404 | } 405 | } 406 | } 407 | 408 | protected float TryChangeSizeOfInternal( IPanelGroupElement element, Direction direction, float deltaSize ) 409 | { 410 | int currResizePropsIndex = resizePropsIndex; 411 | AddResizeProperty( element ); 412 | 413 | float thisFlexibleSize; 414 | if( direction == Direction.Left || direction == Direction.Right ) 415 | thisFlexibleSize = element.Size.x - element.MinSize.x; 416 | else 417 | thisFlexibleSize = element.Size.y - element.MinSize.y; 418 | 419 | if( thisFlexibleSize > MIN_SIZE_TOLERANCE ) 420 | { 421 | if( thisFlexibleSize >= deltaSize ) 422 | { 423 | thisFlexibleSize = deltaSize; 424 | deltaSize = 0f; 425 | } 426 | else 427 | deltaSize -= thisFlexibleSize; 428 | 429 | ResizeElementHelper( currResizePropsIndex, direction.Opposite(), -thisFlexibleSize ); 430 | } 431 | else 432 | thisFlexibleSize = 0f; 433 | 434 | if( deltaSize > MIN_SIZE_TOLERANCE ) 435 | { 436 | IPanelGroupElement surrounding = element.GetSurroundingElement( direction ); 437 | if( !surrounding.IsNull() ) 438 | { 439 | if( surrounding.Group != element.Group ) 440 | AddResizeProperty( surrounding.GetSurroundingElement( direction.Opposite() ) ); 441 | 442 | float deltaMovement = TryChangeSizeOfInternal( surrounding, direction, deltaSize ); 443 | if( deltaMovement > MIN_SIZE_TOLERANCE ) 444 | { 445 | if( surrounding.Group == element.Group ) 446 | { 447 | if( direction == Direction.Left ) 448 | resizeProperties[currResizePropsIndex].posX -= deltaMovement; 449 | else if( direction == Direction.Top ) 450 | resizeProperties[currResizePropsIndex].posY += deltaMovement; 451 | else if( direction == Direction.Right ) 452 | resizeProperties[currResizePropsIndex].posX += deltaMovement; 453 | else 454 | resizeProperties[currResizePropsIndex].posY -= deltaMovement; 455 | 456 | thisFlexibleSize += deltaMovement; 457 | } 458 | else 459 | ResizeElementHelper( currResizePropsIndex + 1, direction, deltaMovement ); 460 | } 461 | else 462 | { 463 | if( thisFlexibleSize == 0f ) 464 | resizePropsIndex = currResizePropsIndex; 465 | else 466 | resizePropsIndex = currResizePropsIndex + 1; 467 | } 468 | } 469 | else if( thisFlexibleSize == 0f ) 470 | resizePropsIndex = currResizePropsIndex; 471 | } 472 | 473 | return thisFlexibleSize; 474 | } 475 | 476 | private void AddResizeProperty( IPanelGroupElement element ) 477 | { 478 | if( resizeProperties == null ) 479 | resizeProperties = new List() { new ElementDirtyProperties( element ), new ElementDirtyProperties() }; 480 | else if( resizePropsIndex == resizeProperties.Count ) 481 | resizeProperties.Add( new ElementDirtyProperties( element ) ); 482 | else 483 | resizeProperties[resizePropsIndex].Reset( element ); 484 | 485 | resizePropsIndex++; 486 | } 487 | 488 | private void ResizeElementHelper( int resizePropsIndex, Direction direction, float deltaSize ) 489 | { 490 | ElementDirtyProperties properties = resizeProperties[resizePropsIndex]; 491 | 492 | if( direction == Direction.Left ) 493 | { 494 | properties.posX -= deltaSize; 495 | properties.sizeX += deltaSize; 496 | } 497 | else if( direction == Direction.Top ) 498 | properties.sizeY += deltaSize; 499 | else if( direction == Direction.Right ) 500 | properties.sizeX += deltaSize; 501 | else 502 | { 503 | properties.posY -= deltaSize; 504 | properties.sizeY += deltaSize; 505 | } 506 | } 507 | 508 | protected void ReplaceElement( IPanelGroupElement beforeElement, IPanelGroupElement afterElement ) 509 | { 510 | if( beforeElement == afterElement ) 511 | return; 512 | 513 | if( beforeElement.IsNull() || afterElement.IsNull() ) 514 | { 515 | Debug.LogError( "Invalid argument!" ); 516 | return; 517 | } 518 | 519 | int index = elements.IndexOf( beforeElement ); 520 | if( index < 0 ) 521 | { 522 | Debug.LogError( "Invalid index!" ); 523 | return; 524 | } 525 | 526 | if( beforeElement.Group == this ) 527 | Canvas.UnanchoredPanelGroup.AddElement( beforeElement ); 528 | 529 | AddElementAt( index, afterElement ); 530 | } 531 | 532 | public void ResizeTo( Vector2 newSize, Direction horizontalDir = Direction.Right, Direction verticalDir = Direction.Bottom ) 533 | { 534 | if( Group != null ) 535 | Group.ResizeElementTo( this, newSize, horizontalDir, verticalDir ); 536 | } 537 | 538 | public void DockToRoot( Direction direction ) 539 | { 540 | PanelManager.Instance.AnchorPanel( this, Canvas, direction ); 541 | } 542 | 543 | public void DockToPanel( IPanelGroupElement anchor, Direction direction ) 544 | { 545 | PanelManager.Instance.AnchorPanel( this, anchor, direction ); 546 | } 547 | 548 | public void AddElement( IPanelGroupElement element ) 549 | { 550 | AddElementAt( elements.Count, element ); 551 | } 552 | 553 | public void AddElementBefore( IPanelGroupElement pivot, IPanelGroupElement element ) 554 | { 555 | AddElementAt( elements.IndexOf( pivot ), element ); 556 | } 557 | 558 | public void AddElementAfter( IPanelGroupElement pivot, IPanelGroupElement element ) 559 | { 560 | AddElementAt( elements.IndexOf( pivot ) + 1, element ); 561 | } 562 | 563 | protected void AddElementAt( int index, IPanelGroupElement element ) 564 | { 565 | if( element.IsNull() ) 566 | { 567 | Debug.LogError( "Invalid argument!" ); 568 | return; 569 | } 570 | 571 | if( index < 0 || index > elements.Count ) 572 | { 573 | Debug.LogError( "Invalid index!" ); 574 | return; 575 | } 576 | 577 | int elementIndex = elements.IndexOf( element ); 578 | if( elementIndex >= 0 && element.Group != this ) 579 | { 580 | if( index > elementIndex ) 581 | index--; 582 | 583 | elements.RemoveAt( elementIndex ); 584 | elementIndex = -1; 585 | } 586 | 587 | if( elementIndex == index ) 588 | return; 589 | 590 | if( element.Group != null ) 591 | element.Group.SetDirty(); 592 | 593 | if( elementIndex < 0 ) 594 | { 595 | // Element not present in this group, add it 596 | elements.Insert( index, element ); 597 | SetGroupFor( element, this ); 598 | } 599 | else if( elementIndex != index ) 600 | { 601 | // Element already present in this group, just change its index 602 | if( elementIndex > index ) 603 | elementIndex++; 604 | 605 | elements.Insert( index, element ); 606 | elements.RemoveAt( elementIndex ); 607 | } 608 | 609 | SetDirty(); 610 | } 611 | 612 | protected void SetGroupFor( IPanelGroupElement element, PanelGroup group ) 613 | { 614 | Panel panel = element as Panel; 615 | if( panel != null ) 616 | { 617 | panel.Internal.Group = group; 618 | 619 | if( panel.RectTransform.parent != group.Canvas.RectTransform ) 620 | panel.RectTransform.SetParent( group.Canvas.RectTransform, false ); 621 | } 622 | else 623 | ( (PanelGroup) element ).Group = group; 624 | } 625 | 626 | protected void UpdateBoundsOf( IPanelGroupElement element, Vector2 position, Vector2 size ) 627 | { 628 | if( element is Panel ) 629 | ( (Panel) element ).Internal.UpdateBounds( position, size ); 630 | else 631 | ( (PanelGroup) element ).UpdateBounds( position, size ); 632 | } 633 | 634 | public override string ToString() 635 | { 636 | if( direction == Direction.Left || direction == Direction.Right ) 637 | return "Horizontal Group"; 638 | 639 | return "Vertical Group"; 640 | } 641 | 642 | // Debug function to print the current hierarchy of groups to console 643 | public void PrintHierarchy() 644 | { 645 | Debug.Log( ToTree( 0, new System.Text.StringBuilder( 500 ) ) ); 646 | } 647 | 648 | private string ToTree( int depth, System.Text.StringBuilder treeBuilder ) 649 | { 650 | string prefix = string.Empty; 651 | for( int i = 0; i <= depth; i++ ) 652 | prefix += "-"; 653 | 654 | treeBuilder.Append( depth ).Append( prefix ).Append( ' ' ).Append( this ).Append( System.Environment.NewLine ); 655 | 656 | foreach( var element in elements ) 657 | { 658 | if( element is Panel ) 659 | treeBuilder.Append( depth + 1 ).Append( prefix ).Append( "- " ).Append( element ).Append( System.Environment.NewLine ); 660 | else 661 | ( (PanelGroup) element ).ToTree( depth + 1, treeBuilder ); 662 | } 663 | 664 | return depth == 0 ? treeBuilder.ToString() : null; 665 | } 666 | } 667 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping/PanelGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c18ac0bffdbf7544ab984f13e0643cd7 3 | timeCreated: 1504794374 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping/UnanchoredPanelGroup.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace DynamicPanels 4 | { 5 | public class UnanchoredPanelGroup : PanelGroup 6 | { 7 | public UnanchoredPanelGroup( DynamicPanelsCanvas canvas ) : base( canvas, Direction.None ) 8 | { 9 | } 10 | 11 | protected override void UpdateBounds( Vector2 position, Vector2 size ) 12 | { 13 | for( int i = 0; i < elements.Count; i++ ) 14 | { 15 | if( elements[i] is Panel ) 16 | RestrictPanelToBounds( (Panel) elements[i], size ); 17 | } 18 | } 19 | 20 | protected override void UpdateLayout() 21 | { 22 | bool wasDirty = isDirty; 23 | 24 | base.UpdateLayout(); 25 | 26 | if( wasDirty ) 27 | { 28 | for( int i = elements.Count - 1; i >= 0; i-- ) 29 | { 30 | PanelGroup subGroup = elements[i] as PanelGroup; 31 | if( subGroup != null ) 32 | { 33 | elements.RemoveAt( i ); 34 | 35 | for( int j = 0; j < subGroup.Count; j++, i++ ) 36 | { 37 | elements.Insert( i, subGroup[j] ); 38 | SetGroupFor( elements[i], this ); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | 45 | protected override void EnsureMinimumSizeOf( IPanelGroupElement element ) 46 | { 47 | Panel panel = element as Panel; 48 | if( !panel ) 49 | return; 50 | 51 | Vector2 position = panel.Position; 52 | 53 | Vector2 size = panel.Size; 54 | Vector2 minSize = panel.MinSize; 55 | 56 | bool hasChanged = false; 57 | 58 | float flexibleWidth = size.x - minSize.x; 59 | if( flexibleWidth < -MIN_SIZE_TOLERANCE ) 60 | { 61 | size.x -= flexibleWidth; 62 | position.x += flexibleWidth * 0.5f; 63 | 64 | hasChanged = true; 65 | } 66 | 67 | float flexibleHeight = size.y - minSize.y; 68 | if( flexibleHeight < -MIN_SIZE_TOLERANCE ) 69 | { 70 | size.y -= flexibleHeight; 71 | position.y += flexibleHeight * 0.5f; 72 | 73 | hasChanged = true; 74 | } 75 | 76 | if( hasChanged ) 77 | { 78 | panel.Internal.UpdateBounds( position, size ); 79 | RestrictPanelToBounds( panel ); 80 | } 81 | } 82 | 83 | public void RestrictPanelToBounds( Panel panel ) 84 | { 85 | RestrictPanelToBounds( panel, Canvas.Size ); 86 | } 87 | 88 | protected void RestrictPanelToBounds( Panel panel, Vector2 canvasSize ) 89 | { 90 | Vector2 panelPosition = panel.RectTransform.anchoredPosition; 91 | Vector2 panelSize = panel.RectTransform.sizeDelta; 92 | 93 | if( panelPosition.y + panelSize.y < 50f ) 94 | panelPosition.y = 50f - panelSize.y; 95 | else if( panelPosition.y + panelSize.y > canvasSize.y ) 96 | panelPosition.y = canvasSize.y - panelSize.y; 97 | 98 | if( panelPosition.x < 0f ) 99 | panelPosition.x = 0f; 100 | else if( canvasSize.x - panelPosition.x < 125f ) 101 | panelPosition.x = canvasSize.x - 125f; 102 | 103 | panel.RectTransform.anchoredPosition = panelPosition; 104 | } 105 | 106 | public override string ToString() 107 | { 108 | return "Unanchored Panel Group"; 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Grouping/UnanchoredPanelGroup.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3a9600d0b607a204aaa4aefdfb6ab780 3 | timeCreated: 1520949278 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f470c03715867be41913342c05a6e68f 3 | folderAsset: yes 4 | timeCreated: 1507479811 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/NonDrawingGraphic.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.UI; 3 | 4 | namespace DynamicPanels 5 | { 6 | // Credit: http://answers.unity.com/answers/1157876/view.html 7 | [RequireComponent( typeof( CanvasRenderer ) )] 8 | public class NonDrawingGraphic : Graphic 9 | { 10 | public override void SetMaterialDirty() { return; } 11 | public override void SetVerticesDirty() { return; } 12 | 13 | protected override void OnPopulateMesh( VertexHelper vh ) 14 | { 15 | vh.Clear(); 16 | return; 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/NonDrawingGraphic.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 431fbefef6492614d84f825f4532d64e 3 | timeCreated: 1572700126 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelCursorHandler.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | 4 | namespace DynamicPanels 5 | { 6 | public class PanelCursorHandler : MonoBehaviour 7 | { 8 | private static PanelCursorHandler instance = null; 9 | 10 | private PanelResizeHelper activeResizeHelper; 11 | private PointerEventData activeEventData; 12 | 13 | private bool isResizing; 14 | private Vector2 prevPointerPos; 15 | 16 | #pragma warning disable 0649 17 | [SerializeField] 18 | private Texture2D horizontalCursor; 19 | [SerializeField] 20 | private Texture2D verticalCursor; 21 | [SerializeField] 22 | private Texture2D diagonalCursorTopLeft; 23 | [SerializeField] 24 | private Texture2D diagonalCursorTopRight; 25 | #pragma warning restore 0649 26 | 27 | private void Awake() 28 | { 29 | instance = this; 30 | } 31 | 32 | public static void OnPointerEnter( PanelResizeHelper resizeHelper, PointerEventData eventData ) 33 | { 34 | if( instance == null ) 35 | return; 36 | 37 | instance.activeResizeHelper = resizeHelper; 38 | instance.activeEventData = eventData; 39 | } 40 | 41 | public static void OnPointerExit( PanelResizeHelper resizeHelper ) 42 | { 43 | if( instance == null ) 44 | return; 45 | 46 | if( instance.activeResizeHelper == resizeHelper ) 47 | { 48 | instance.activeResizeHelper = null; 49 | instance.activeEventData = null; 50 | 51 | if( !instance.isResizing ) 52 | SetDefaultCursor(); 53 | } 54 | } 55 | 56 | public static void OnBeginResize( Direction primary, Direction secondary ) 57 | { 58 | if( instance == null ) 59 | return; 60 | 61 | instance.isResizing = true; 62 | instance.UpdateCursor( primary, secondary ); 63 | } 64 | 65 | public static void OnEndResize() 66 | { 67 | if( instance == null ) 68 | return; 69 | 70 | instance.isResizing = false; 71 | 72 | if( instance.activeResizeHelper == null ) 73 | SetDefaultCursor(); 74 | else 75 | instance.prevPointerPos = new Vector2( -1f, -1f ); 76 | } 77 | 78 | private void Update() 79 | { 80 | if( isResizing ) 81 | return; 82 | 83 | if( activeResizeHelper != null ) 84 | { 85 | Vector2 pointerPos = activeEventData.position; 86 | if( pointerPos != prevPointerPos ) 87 | { 88 | if( activeEventData.dragging ) 89 | SetDefaultCursor(); 90 | else 91 | { 92 | Direction direction = activeResizeHelper.Direction; 93 | Direction secondDirection = activeResizeHelper.GetSecondDirection( activeEventData.position ); 94 | if( activeResizeHelper.Panel.CanResizeInDirection( direction ) ) 95 | UpdateCursor( direction, secondDirection ); 96 | else if( secondDirection != Direction.None ) 97 | UpdateCursor( secondDirection, Direction.None ); 98 | else 99 | SetDefaultCursor(); 100 | } 101 | 102 | prevPointerPos = pointerPos; 103 | } 104 | } 105 | } 106 | 107 | private static void SetDefaultCursor() 108 | { 109 | Cursor.SetCursor( null, Vector2.zero, CursorMode.Auto ); 110 | } 111 | 112 | private void UpdateCursor( Direction primary, Direction secondary ) 113 | { 114 | Texture2D cursorTex; 115 | if( primary == Direction.Left ) 116 | { 117 | if( secondary == Direction.Top ) 118 | cursorTex = diagonalCursorTopLeft; 119 | else if( secondary == Direction.Bottom ) 120 | cursorTex = diagonalCursorTopRight; 121 | else 122 | cursorTex = horizontalCursor; 123 | } 124 | else if( primary == Direction.Right ) 125 | { 126 | if( secondary == Direction.Top ) 127 | cursorTex = diagonalCursorTopRight; 128 | else if( secondary == Direction.Bottom ) 129 | cursorTex = diagonalCursorTopLeft; 130 | else 131 | cursorTex = horizontalCursor; 132 | } 133 | else if( primary == Direction.Top ) 134 | { 135 | if( secondary == Direction.Left ) 136 | cursorTex = diagonalCursorTopLeft; 137 | else if( secondary == Direction.Right ) 138 | cursorTex = diagonalCursorTopRight; 139 | else 140 | cursorTex = verticalCursor; 141 | } 142 | else 143 | { 144 | if( secondary == Direction.Left ) 145 | cursorTex = diagonalCursorTopRight; 146 | else if( secondary == Direction.Right ) 147 | cursorTex = diagonalCursorTopLeft; 148 | else 149 | cursorTex = verticalCursor; 150 | } 151 | 152 | Cursor.SetCursor( cursorTex, new Vector2( cursorTex.width * 0.5f, cursorTex.height * 0.5f ), CursorMode.Auto ); 153 | } 154 | } 155 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelCursorHandler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 13f43f7a9474ed54489e906030258e3c 3 | timeCreated: 1550766107 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: 8 | - horizontalCursor: {fileID: 2800000, guid: a9c77eeb970c9ae40a370ca7060be120, type: 3} 9 | - verticalCursor: {fileID: 2800000, guid: 68ac78481f5b6df4da69a6f5133b6702, type: 3} 10 | - diagonalCursorTopLeft: {fileID: 2800000, guid: cbaa205f7a905b8429011ee0c50015ea, 11 | type: 3} 12 | - diagonalCursorTopRight: {fileID: 2800000, guid: e5a757b3ef912a24c912a99d9e1befe5, 13 | type: 3} 14 | executionOrder: 0 15 | icon: {instanceID: 0} 16 | userData: 17 | assetBundleName: 18 | assetBundleVariant: 19 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelHeader.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | 4 | namespace DynamicPanels 5 | { 6 | [DisallowMultipleComponent] 7 | public class PanelHeader : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler 8 | { 9 | #pragma warning disable 0649 10 | [SerializeField] 11 | private Panel m_panel; 12 | public Panel Panel { get { return m_panel; } } 13 | #pragma warning restore 0649 14 | 15 | private int pointerId = PanelManager.NON_EXISTING_TOUCH; 16 | 17 | private Vector2 m_initialTouchPos; 18 | internal Vector2 InitialTouchPos { get { return m_initialTouchPos; } } 19 | 20 | private void OnEnable() 21 | { 22 | pointerId = PanelManager.NON_EXISTING_TOUCH; 23 | } 24 | 25 | public void OnBeginDrag( PointerEventData eventData ) 26 | { 27 | if( !PanelManager.Instance.OnBeginPanelTranslate( m_panel ) ) 28 | { 29 | eventData.pointerDrag = null; 30 | return; 31 | } 32 | 33 | pointerId = eventData.pointerId; 34 | RectTransformUtility.ScreenPointToLocalPointInRectangle( m_panel.RectTransform, eventData.position, m_panel.Canvas.Internal.worldCamera, out m_initialTouchPos ); 35 | } 36 | 37 | public void OnDrag( PointerEventData eventData ) 38 | { 39 | if( eventData.pointerId != pointerId ) 40 | { 41 | eventData.pointerDrag = null; 42 | return; 43 | } 44 | 45 | PanelManager.Instance.OnPanelTranslate( this, eventData ); 46 | } 47 | 48 | public void OnEndDrag( PointerEventData eventData ) 49 | { 50 | if( eventData.pointerId != pointerId ) 51 | return; 52 | 53 | pointerId = PanelManager.NON_EXISTING_TOUCH; 54 | PanelManager.Instance.OnEndPanelTranslate( m_panel ); 55 | } 56 | 57 | public void Stop() 58 | { 59 | pointerId = PanelManager.NON_EXISTING_TOUCH; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelHeader.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 034581b0eae396a48b005bc2114633f2 3 | timeCreated: 1503993560 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelNotificationCenter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | 4 | namespace DynamicPanels 5 | { 6 | public static class PanelNotificationCenter 7 | { 8 | internal static class Internal 9 | { 10 | public static void PanelCreated( Panel panel ) 11 | { 12 | if( !IsPanelRegistered( panel ) ) 13 | { 14 | panels.Add( panel ); 15 | 16 | panel.Internal.ChangeCloseButtonVisibility( m_onPanelClosed != null ); 17 | 18 | if( OnPanelCreated != null ) 19 | OnPanelCreated( panel ); 20 | 21 | if( panel.gameObject.activeInHierarchy ) 22 | { 23 | if( OnPanelBecameActive != null ) 24 | OnPanelBecameActive( panel ); 25 | } 26 | else 27 | { 28 | if( OnPanelBecameInactive != null ) 29 | OnPanelBecameInactive( panel ); 30 | } 31 | } 32 | } 33 | 34 | public static void PanelDestroyed( Panel panel ) 35 | { 36 | if( panels.Remove( panel ) && OnPanelDestroyed != null ) 37 | OnPanelDestroyed( panel ); 38 | } 39 | 40 | public static void PanelBecameActive( Panel panel ) 41 | { 42 | if( IsPanelRegistered( panel ) ) 43 | { 44 | if( OnPanelBecameActive != null ) 45 | OnPanelBecameActive( panel ); 46 | } 47 | } 48 | 49 | public static void PanelBecameInactive( Panel panel ) 50 | { 51 | if( IsPanelRegistered( panel ) ) 52 | { 53 | if( OnPanelBecameInactive != null ) 54 | OnPanelBecameInactive( panel ); 55 | } 56 | } 57 | 58 | public static void PanelClosed( Panel panel ) 59 | { 60 | if( m_onPanelClosed != null ) 61 | m_onPanelClosed( panel ); 62 | } 63 | 64 | public static void TabDragStateChanged( PanelTab tab, bool isDragging ) 65 | { 66 | if( isDragging ) 67 | { 68 | if( OnStartedDraggingTab != null ) 69 | OnStartedDraggingTab( tab ); 70 | } 71 | else 72 | { 73 | if( OnStoppedDraggingTab != null ) 74 | OnStoppedDraggingTab( tab ); 75 | } 76 | } 77 | 78 | public static void ActiveTabChanged( PanelTab tab ) 79 | { 80 | if( OnActiveTabChanged != null ) 81 | OnActiveTabChanged( tab ); 82 | } 83 | 84 | public static void TabIDChanged( PanelTab tab, string previousID, string newID ) 85 | { 86 | if( !idToTab.ContainsValue( tab ) ) 87 | { 88 | tab.Internal.ChangeCloseButtonVisibility( m_onTabClosed != null ); 89 | 90 | if( OnTabCreated != null ) 91 | OnTabCreated( tab ); 92 | } 93 | 94 | if( !string.IsNullOrEmpty( previousID ) ) 95 | { 96 | PanelTab previousTab; 97 | if( idToTab.TryGetValue( previousID, out previousTab ) && previousTab == tab ) 98 | idToTab.Remove( previousID ); 99 | } 100 | 101 | if( !string.IsNullOrEmpty( newID ) ) 102 | idToTab[newID] = tab; 103 | else if( OnTabDestroyed != null ) 104 | OnTabDestroyed( tab ); 105 | } 106 | 107 | public static void TabClosed( PanelTab tab ) 108 | { 109 | if( m_onTabClosed != null ) 110 | m_onTabClosed( tab ); 111 | } 112 | 113 | private static bool IsPanelRegistered( Panel panel ) 114 | { 115 | for( int i = panels.Count - 1; i >= 0; i-- ) 116 | { 117 | if( panels[i] == panel ) 118 | return true; 119 | } 120 | 121 | return false; 122 | } 123 | } 124 | 125 | public delegate void PanelDelegate( Panel panel ); 126 | public delegate void TabDelegate( PanelTab tab ); 127 | 128 | public static event PanelDelegate OnPanelCreated, OnPanelDestroyed, OnPanelBecameActive, OnPanelBecameInactive; 129 | public static event TabDelegate OnTabCreated, OnTabDestroyed, OnActiveTabChanged, OnStartedDraggingTab, OnStoppedDraggingTab; 130 | 131 | private static PanelDelegate m_onPanelClosed; 132 | public static event PanelDelegate OnPanelClosed 133 | { 134 | add 135 | { 136 | if( value != null ) 137 | { 138 | if( m_onPanelClosed == null ) 139 | { 140 | for( int i = panels.Count - 1; i >= 0; i-- ) 141 | panels[i].Internal.ChangeCloseButtonVisibility( true ); 142 | } 143 | 144 | m_onPanelClosed += value; 145 | } 146 | } 147 | remove 148 | { 149 | if( value != null && m_onPanelClosed != null ) 150 | { 151 | m_onPanelClosed -= value; 152 | 153 | if( m_onPanelClosed == null ) 154 | { 155 | for( int i = panels.Count - 1; i >= 0; i-- ) 156 | panels[i].Internal.ChangeCloseButtonVisibility( false ); 157 | } 158 | } 159 | } 160 | } 161 | 162 | private static TabDelegate m_onTabClosed; 163 | public static event TabDelegate OnTabClosed 164 | { 165 | add 166 | { 167 | if( value != null ) 168 | { 169 | if( m_onTabClosed == null ) 170 | { 171 | foreach( PanelTab tab in idToTab.Values ) 172 | tab.Internal.ChangeCloseButtonVisibility( true ); 173 | } 174 | 175 | m_onTabClosed += value; 176 | } 177 | } 178 | remove 179 | { 180 | if( value != null && m_onTabClosed != null ) 181 | { 182 | m_onTabClosed -= value; 183 | 184 | if( m_onTabClosed == null ) 185 | { 186 | foreach( PanelTab tab in idToTab.Values ) 187 | tab.Internal.ChangeCloseButtonVisibility( false ); 188 | } 189 | } 190 | } 191 | } 192 | 193 | private static readonly List panels = new List( 32 ); 194 | public static int NumberOfPanels { get { return panels.Count; } } 195 | 196 | private static readonly Dictionary idToTab = new Dictionary( 32 ); 197 | 198 | [RuntimeInitializeOnLoadMethod( RuntimeInitializeLoadType.SubsystemRegistration )] // Configurable Enter Play Mode: https://docs.unity3d.com/Manual/DomainReloading.html 199 | private static void ResetStatics() 200 | { 201 | OnPanelCreated = null; 202 | OnPanelDestroyed = null; 203 | OnPanelBecameActive = null; 204 | OnPanelBecameInactive = null; 205 | OnTabCreated = null; 206 | OnTabDestroyed = null; 207 | OnActiveTabChanged = null; 208 | OnStartedDraggingTab = null; 209 | OnStoppedDraggingTab = null; 210 | m_onPanelClosed = null; 211 | m_onTabClosed = null; 212 | 213 | panels.Clear(); 214 | idToTab.Clear(); 215 | } 216 | 217 | public static Panel GetPanel( int panelIndex ) 218 | { 219 | if( panelIndex >= 0 && panelIndex < panels.Count ) 220 | return panels[panelIndex]; 221 | 222 | return null; 223 | } 224 | 225 | public static bool TryGetTab( string tabID, out PanelTab tab ) 226 | { 227 | if( string.IsNullOrEmpty( tabID ) ) 228 | { 229 | tab = null; 230 | return false; 231 | } 232 | 233 | return idToTab.TryGetValue( tabID, out tab ); 234 | } 235 | } 236 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelNotificationCenter.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 598dda653ba7b9040a4eb8aac5ab2fff 3 | timeCreated: 1525200156 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelResizeHelper.cs: -------------------------------------------------------------------------------- 1 | #if UNITY_EDITOR || ( !UNITY_ANDROID && !UNITY_IOS ) 2 | #define ENABLE_CURSOR_MANAGEMENT 3 | #endif 4 | 5 | using UnityEngine; 6 | using UnityEngine.EventSystems; 7 | 8 | namespace DynamicPanels 9 | { 10 | [DisallowMultipleComponent] 11 | public class PanelResizeHelper : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler 12 | #if ENABLE_CURSOR_MANAGEMENT 13 | , IPointerEnterHandler, IPointerExitHandler 14 | #endif 15 | { 16 | private Panel m_panel; 17 | public Panel Panel { get { return m_panel; } } 18 | 19 | public RectTransform RectTransform { get; private set; } 20 | 21 | private Direction m_direction; 22 | private Direction secondDirection; 23 | 24 | public Direction Direction { get { return m_direction; } } 25 | 26 | private PanelResizeHelper helperBefore, helperAfter; 27 | 28 | private int pointerId = PanelManager.NON_EXISTING_TOUCH; 29 | 30 | private void Awake() 31 | { 32 | RectTransform = (RectTransform) transform; 33 | } 34 | 35 | private void OnEnable() 36 | { 37 | pointerId = PanelManager.NON_EXISTING_TOUCH; 38 | } 39 | 40 | public void Initialize( Panel panel, Direction direction, PanelResizeHelper helperBefore, PanelResizeHelper helperAfter ) 41 | { 42 | m_panel = panel; 43 | 44 | this.m_direction = direction; 45 | this.helperBefore = helperBefore; 46 | this.helperAfter = helperAfter; 47 | } 48 | 49 | #if ENABLE_CURSOR_MANAGEMENT 50 | public void OnPointerEnter( PointerEventData eventData ) 51 | { 52 | PanelCursorHandler.OnPointerEnter( this, eventData ); 53 | } 54 | 55 | public void OnPointerExit( PointerEventData eventData ) 56 | { 57 | PanelCursorHandler.OnPointerExit( this ); 58 | } 59 | #endif 60 | 61 | public void OnBeginDrag( PointerEventData eventData ) 62 | { 63 | // Cancel drag event if panel is already being resized by another pointer 64 | // or panel is anchored to a fixed anchor in that direction 65 | if( !m_panel.CanResizeInDirection( m_direction ) ) 66 | { 67 | eventData.pointerDrag = null; 68 | return; 69 | } 70 | 71 | pointerId = eventData.pointerId; 72 | secondDirection = GetSecondDirection( eventData.pressPosition ); 73 | 74 | #if ENABLE_CURSOR_MANAGEMENT 75 | PanelCursorHandler.OnBeginResize( m_direction, secondDirection ); 76 | #endif 77 | } 78 | 79 | public void OnDrag( PointerEventData eventData ) 80 | { 81 | if( eventData.pointerId != pointerId ) 82 | return; 83 | 84 | m_panel.Internal.OnResize( m_direction, eventData.position ); 85 | 86 | if( secondDirection != Direction.None ) 87 | m_panel.Internal.OnResize( secondDirection, eventData.position ); 88 | } 89 | 90 | public void OnEndDrag( PointerEventData eventData ) 91 | { 92 | if( eventData.pointerId != pointerId ) 93 | return; 94 | 95 | if( !m_panel.IsDocked ) 96 | ( (UnanchoredPanelGroup) m_panel.Group ).RestrictPanelToBounds( m_panel ); 97 | 98 | pointerId = PanelManager.NON_EXISTING_TOUCH; 99 | 100 | #if ENABLE_CURSOR_MANAGEMENT 101 | PanelCursorHandler.OnEndResize(); 102 | #endif 103 | } 104 | 105 | public Direction GetSecondDirection( Vector2 pointerPosition ) 106 | { 107 | if( m_panel.IsDocked ) 108 | return Direction.None; 109 | 110 | Direction result; 111 | if( RectTransformUtility.RectangleContainsScreenPoint( helperBefore.RectTransform, pointerPosition, m_panel.Canvas.Internal.worldCamera ) ) 112 | result = helperBefore.m_direction; 113 | else if( RectTransformUtility.RectangleContainsScreenPoint( helperAfter.RectTransform, pointerPosition, m_panel.Canvas.Internal.worldCamera ) ) 114 | result = helperAfter.m_direction; 115 | else 116 | result = Direction.None; 117 | 118 | if( !m_panel.CanResizeInDirection( result ) ) 119 | result = Direction.None; 120 | 121 | return result; 122 | } 123 | 124 | public void Stop() 125 | { 126 | if( pointerId != PanelManager.NON_EXISTING_TOUCH ) 127 | { 128 | if( !m_panel.IsDocked ) 129 | ( (UnanchoredPanelGroup) m_panel.Group ).RestrictPanelToBounds( m_panel ); 130 | 131 | pointerId = PanelManager.NON_EXISTING_TOUCH; 132 | 133 | #if ENABLE_CURSOR_MANAGEMENT 134 | PanelCursorHandler.OnEndResize(); 135 | #endif 136 | } 137 | } 138 | } 139 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelResizeHelper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 09b78c3b175f33d4bbe3950ba0f01921 3 | timeCreated: 1503918646 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelSerialization.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.Serialization.Formatters.Binary; 5 | using UnityEngine; 6 | 7 | namespace DynamicPanels 8 | { 9 | public static class PanelSerialization 10 | { 11 | #region Helper Classes 12 | #pragma warning disable 0649 13 | [Serializable] 14 | private class SerializedCanvas 15 | { 16 | public bool active; 17 | public bool useFreeSpace; 18 | 19 | public SerializedPanelGroup rootPanelGroup; 20 | public SerializedPanelGroup unanchoredPanelGroup; 21 | } 22 | 23 | [Serializable] 24 | private abstract class ISerializedElement 25 | { 26 | public SerializedVector2 size; 27 | } 28 | 29 | [Serializable] 30 | private class SerializedPanelGroup : ISerializedElement 31 | { 32 | public bool horizontal; 33 | public ISerializedElement[] children; 34 | } 35 | 36 | [Serializable] 37 | private class SerializedDummyPanel : ISerializedElement 38 | { 39 | } 40 | 41 | [Serializable] 42 | private class SerializedPanel : ISerializedElement 43 | { 44 | public int activeTab; 45 | public SerializedPanelTab[] tabs; 46 | public SerializedVector2 floatingSize; 47 | } 48 | 49 | [Serializable] 50 | private class SerializedUnanchoredPanel : SerializedPanel 51 | { 52 | public bool active; 53 | public SerializedVector2 position; 54 | } 55 | 56 | [Serializable] 57 | private class SerializedPanelTab 58 | { 59 | public string id; 60 | //public SerializedVector2 minSize; 61 | //public string label; 62 | } 63 | 64 | [Serializable] 65 | private struct SerializedVector2 66 | { 67 | public float x, y; 68 | 69 | public static implicit operator Vector2( SerializedVector2 v ) 70 | { 71 | return new Vector2( v.x, v.y ); 72 | } 73 | 74 | public static implicit operator SerializedVector2( Vector2 v ) 75 | { 76 | return new SerializedVector2() { x = v.x, y = v.y }; 77 | } 78 | } 79 | 80 | private struct GroupElementSizeHolder 81 | { 82 | public IPanelGroupElement element; 83 | public Vector2 size; 84 | 85 | public GroupElementSizeHolder( IPanelGroupElement element, Vector2 size ) 86 | { 87 | this.element = element; 88 | this.size = size; 89 | } 90 | } 91 | #pragma warning restore 0649 92 | #endregion 93 | 94 | private static readonly List tabsTemp = new List( 4 ); 95 | private static readonly List sizesHolder = new List( 4 ); 96 | 97 | public static void SerializeCanvas( DynamicPanelsCanvas canvas ) 98 | { 99 | byte[] data = SerializeCanvasToArray( canvas ); 100 | if( data == null || data.Length == 0 ) 101 | { 102 | Debug.LogError( "Couldn't serialize!" ); 103 | return; 104 | } 105 | 106 | PlayerPrefs.SetString( canvas.ID, Convert.ToBase64String( data ) ); 107 | PlayerPrefs.Save(); 108 | } 109 | 110 | public static void DeserializeCanvas( DynamicPanelsCanvas canvas ) 111 | { 112 | DeserializeCanvasFromArray( canvas, Convert.FromBase64String( PlayerPrefs.GetString( canvas.ID, string.Empty ) ) ); 113 | } 114 | 115 | public static byte[] SerializeCanvasToArray( DynamicPanelsCanvas canvas ) 116 | { 117 | #if UNITY_EDITOR 118 | if( !Application.isPlaying ) 119 | { 120 | Debug.LogError( "Can serialize in Play mode only!" ); 121 | return null; 122 | } 123 | #endif 124 | 125 | canvas.ForceRebuildLayoutImmediate(); 126 | 127 | BinaryFormatter formatter = new BinaryFormatter(); 128 | using( MemoryStream stream = new MemoryStream() ) 129 | { 130 | formatter.Serialize( stream, new SerializedCanvas 131 | { 132 | active = canvas.gameObject.activeSelf, 133 | useFreeSpace = canvas.LeaveFreeSpace, 134 | rootPanelGroup = Serialize( canvas.RootPanelGroup ) as SerializedPanelGroup, 135 | unanchoredPanelGroup = Serialize( canvas.UnanchoredPanelGroup ) as SerializedPanelGroup 136 | } ); 137 | 138 | return stream.ToArray(); 139 | } 140 | } 141 | 142 | public static void DeserializeCanvasFromArray( DynamicPanelsCanvas canvas, byte[] data ) 143 | { 144 | #if UNITY_EDITOR 145 | if( !Application.isPlaying ) 146 | { 147 | Debug.LogError( "Can deserialize in Play mode only!" ); 148 | return; 149 | } 150 | #endif 151 | 152 | if( data == null || data.Length == 0 ) 153 | { 154 | Debug.LogError( "Data is null!" ); 155 | return; 156 | } 157 | 158 | SerializedCanvas serializedCanvas; 159 | BinaryFormatter formatter = new BinaryFormatter(); 160 | using( MemoryStream stream = new MemoryStream( data ) ) 161 | { 162 | serializedCanvas = formatter.Deserialize( stream ) as SerializedCanvas; 163 | } 164 | 165 | if( serializedCanvas == null ) 166 | return; 167 | 168 | sizesHolder.Clear(); 169 | canvas.LeaveFreeSpace = serializedCanvas.useFreeSpace; 170 | 171 | if( serializedCanvas.rootPanelGroup != null ) 172 | { 173 | PanelGroup rootPanelGroup = canvas.RootPanelGroup; 174 | ISerializedElement[] children = serializedCanvas.rootPanelGroup.children; 175 | for( int i = children.Length - 1; i >= 0; i-- ) 176 | { 177 | IPanelGroupElement element = Deserialize( canvas, children[i] ); 178 | if( element != null ) 179 | { 180 | if( rootPanelGroup.Count == 0 ) 181 | rootPanelGroup.AddElement( element ); 182 | else 183 | rootPanelGroup.AddElementBefore( rootPanelGroup[0], element ); 184 | 185 | sizesHolder.Insert( 0, new GroupElementSizeHolder( element, children[i].size ) ); 186 | } 187 | } 188 | } 189 | 190 | if( sizesHolder.Count > 0 ) 191 | { 192 | canvas.ForceRebuildLayoutImmediate(); 193 | 194 | for( int i = 0; i < sizesHolder.Count; i++ ) 195 | sizesHolder[i].element.ResizeTo( sizesHolder[i].size, Direction.Right, Direction.Top ); 196 | } 197 | 198 | if( serializedCanvas.unanchoredPanelGroup != null ) 199 | { 200 | ISerializedElement[] children = serializedCanvas.unanchoredPanelGroup.children; 201 | for( int i = 0; i < children.Length; i++ ) 202 | { 203 | SerializedUnanchoredPanel unanchoredPanel = children[i] as SerializedUnanchoredPanel; 204 | if( unanchoredPanel != null ) 205 | { 206 | Panel panel = Deserialize( canvas, unanchoredPanel ) as Panel; 207 | if( panel != null ) 208 | { 209 | panel.Detach(); 210 | canvas.UnanchoredPanelGroup.RestrictPanelToBounds( panel ); 211 | } 212 | } 213 | } 214 | } 215 | 216 | for( int i = 0; i < canvas.UnanchoredPanelGroup.Count; i++ ) 217 | { 218 | Panel panel = canvas.UnanchoredPanelGroup[i] as Panel; 219 | if( panel != null ) 220 | panel.RectTransform.SetAsLastSibling(); 221 | } 222 | 223 | canvas.gameObject.SetActive( serializedCanvas.active ); 224 | } 225 | 226 | private static ISerializedElement Serialize( IPanelGroupElement element ) 227 | { 228 | if( element == null ) 229 | return null; 230 | 231 | if( element is Panel ) 232 | { 233 | Panel panel = (Panel) element; 234 | if( panel.Internal.IsDummy ) 235 | return new SerializedDummyPanel() { size = panel.Size }; 236 | 237 | tabsTemp.Clear(); 238 | for( int i = 0; i < panel.NumberOfTabs; i++ ) 239 | { 240 | PanelTab tab = panel[i]; 241 | tabsTemp.Add( new SerializedPanelTab() 242 | { 243 | id = tab.ID, 244 | //minSize = tab.MinSize, 245 | //label = tab.Label 246 | } ); 247 | } 248 | 249 | if( tabsTemp.Count == 0 ) 250 | return null; 251 | 252 | if( panel.IsDocked ) 253 | { 254 | return new SerializedPanel() 255 | { 256 | activeTab = panel.ActiveTab, 257 | tabs = tabsTemp.ToArray(), 258 | size = panel.Size, 259 | floatingSize = panel.FloatingSize 260 | }; 261 | } 262 | else 263 | { 264 | return new SerializedUnanchoredPanel() 265 | { 266 | active = panel.gameObject.activeSelf, 267 | activeTab = panel.ActiveTab, 268 | tabs = tabsTemp.ToArray(), 269 | position = panel.Position, 270 | size = panel.Size, 271 | floatingSize = panel.Size 272 | }; 273 | } 274 | } 275 | 276 | PanelGroup panelGroup = (PanelGroup) element; 277 | 278 | ISerializedElement[] children = new ISerializedElement[panelGroup.Count]; 279 | for( int i = 0; i < panelGroup.Count; i++ ) 280 | children[i] = Serialize( panelGroup[i] ); 281 | 282 | return new SerializedPanelGroup() 283 | { 284 | horizontal = panelGroup.IsInSameDirection( Direction.Right ), 285 | children = children, 286 | size = panelGroup.Size 287 | }; 288 | } 289 | 290 | private static IPanelGroupElement Deserialize( DynamicPanelsCanvas canvas, ISerializedElement element ) 291 | { 292 | if( element == null ) 293 | return null; 294 | 295 | if( element is SerializedDummyPanel ) 296 | return canvas.Internal.DummyPanel; 297 | 298 | if( element is SerializedPanel ) 299 | { 300 | SerializedPanel serializedPanel = (SerializedPanel) element; 301 | Panel panel = null; 302 | 303 | SerializedPanelTab[] tabs = serializedPanel.tabs; 304 | for( int i = 0; i < tabs.Length; i++ ) 305 | { 306 | PanelTab tab; 307 | if( !PanelNotificationCenter.TryGetTab( tabs[i].id, out tab ) ) 308 | continue; 309 | 310 | if( panel == null ) 311 | { 312 | panel = tab.Detach(); 313 | canvas.UnanchoredPanelGroup.AddElement( panel ); 314 | } 315 | else 316 | panel.AddTab( tab ); 317 | 318 | //if( tab != null ) 319 | //{ 320 | // tab.MinSize = tabs[i].minSize; 321 | // tab.Label = tabs[i].label; 322 | //} 323 | } 324 | 325 | if( panel != null ) 326 | { 327 | if( serializedPanel.activeTab < tabs.Length ) 328 | { 329 | int activeTabIndex = panel.GetTabIndex( tabs[serializedPanel.activeTab].id ); 330 | if( activeTabIndex >= 0 ) 331 | panel.ActiveTab = activeTabIndex; 332 | } 333 | 334 | if( serializedPanel is SerializedUnanchoredPanel ) 335 | { 336 | SerializedUnanchoredPanel unanchoredPanel = (SerializedUnanchoredPanel) serializedPanel; 337 | panel.RectTransform.anchoredPosition = unanchoredPanel.position; 338 | panel.gameObject.SetActive( unanchoredPanel.active ); 339 | } 340 | 341 | panel.FloatingSize = serializedPanel.floatingSize; 342 | } 343 | 344 | return panel; 345 | } 346 | 347 | if( element is SerializedPanelGroup ) 348 | { 349 | SerializedPanelGroup serializedPanelGroup = (SerializedPanelGroup) element; 350 | ISerializedElement[] children = serializedPanelGroup.children; 351 | if( children == null || children.Length == 0 ) 352 | return null; 353 | 354 | PanelGroup panelGroup = new PanelGroup( canvas, serializedPanelGroup.horizontal ? Direction.Right : Direction.Top ); 355 | for( int i = 0; i < children.Length; i++ ) 356 | { 357 | if( children[i] == null ) 358 | continue; 359 | 360 | IPanelGroupElement childElement = Deserialize( canvas, children[i] ); 361 | if( childElement != null ) 362 | { 363 | panelGroup.AddElement( childElement ); 364 | sizesHolder.Add( new GroupElementSizeHolder( childElement, children[i].size ) ); 365 | } 366 | } 367 | 368 | if( panelGroup.Count > 0 ) 369 | return panelGroup; 370 | } 371 | 372 | return null; 373 | } 374 | } 375 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelSerialization.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed5ab04fcc6d144419468d33ab106597 3 | timeCreated: 1545845208 4 | licenseType: Free 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelTab.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | using UnityEngine.EventSystems; 3 | using UnityEngine.UI; 4 | 5 | namespace DynamicPanels 6 | { 7 | [DisallowMultipleComponent] 8 | public class PanelTab : MonoBehaviour, IPointerClickHandler, IBeginDragHandler, IDragHandler, IEndDragHandler 9 | { 10 | internal class InternalSettings 11 | { 12 | private readonly PanelTab tab; 13 | public readonly RectTransform RectTransform; 14 | 15 | public InternalSettings( PanelTab tab ) 16 | { 17 | this.tab = tab; 18 | RectTransform = (RectTransform) tab.transform; 19 | } 20 | 21 | public bool IsBeingDetached { get { return tab.pointerId != PanelManager.NON_EXISTING_TOUCH; } } 22 | 23 | public void Initialize( Panel panel, RectTransform content ) 24 | { 25 | tab.m_panel = panel; 26 | tab.Content = content; 27 | } 28 | 29 | public void ChangeCloseButtonVisibility( bool isVisible ) 30 | { 31 | if( tab.closeButton && isVisible != tab.closeButton.gameObject.activeSelf ) 32 | { 33 | tab.closeButton.gameObject.SetActive( isVisible ); 34 | 35 | float tabSizeDelta = tab.closeButton.GetComponent().preferredWidth; 36 | tab.GetComponent().preferredWidth += isVisible ? tabSizeDelta : -tabSizeDelta; 37 | } 38 | } 39 | 40 | public void Stop() 41 | { 42 | if( tab.pointerId != PanelManager.NON_EXISTING_TOUCH ) 43 | { 44 | tab.ResetBackgroundColor(); 45 | tab.pointerId = PanelManager.NON_EXISTING_TOUCH; 46 | 47 | PanelNotificationCenter.Internal.TabDragStateChanged( tab, false ); 48 | } 49 | } 50 | 51 | public void SetActive( bool activeState ) { tab.SetActive( activeState ); } 52 | } 53 | 54 | #pragma warning disable 0649 55 | [SerializeField] 56 | private Image background; 57 | 58 | [SerializeField] 59 | private Image iconHolder; 60 | 61 | [SerializeField] 62 | private Text nameHolder; 63 | 64 | [SerializeField] 65 | private Button closeButton; 66 | #pragma warning restore 0649 67 | 68 | internal InternalSettings Internal { get; private set; } 69 | 70 | private string m_id = null; 71 | public string ID 72 | { 73 | get { return m_id; } 74 | set 75 | { 76 | if( !string.IsNullOrEmpty( value ) && m_id != value ) 77 | { 78 | PanelNotificationCenter.Internal.TabIDChanged( this, m_id, value ); 79 | m_id = value; 80 | } 81 | } 82 | } 83 | 84 | private Panel m_panel; 85 | public Panel Panel { get { return m_panel; } } 86 | 87 | public int Index 88 | { 89 | get { return m_panel.GetTabIndex( this ); } 90 | set { m_panel.AddTab( this, value ); } 91 | } 92 | 93 | public RectTransform Content { get; private set; } 94 | 95 | private Vector2 m_minSize; 96 | public Vector2 MinSize 97 | { 98 | get { return m_minSize; } 99 | set 100 | { 101 | if( m_minSize != value ) 102 | { 103 | m_minSize = value; 104 | m_panel.Internal.RecalculateMinSize(); 105 | } 106 | } 107 | } 108 | 109 | public Sprite Icon 110 | { 111 | get { return iconHolder != null ? iconHolder.sprite : null; } 112 | set 113 | { 114 | if( iconHolder != null ) 115 | { 116 | iconHolder.gameObject.SetActive( value != null ); 117 | iconHolder.sprite = value; 118 | } 119 | } 120 | } 121 | 122 | public string Label 123 | { 124 | get { return nameHolder != null ? nameHolder.text : null; } 125 | set 126 | { 127 | if( nameHolder != null && value != null ) 128 | nameHolder.text = value; 129 | } 130 | } 131 | 132 | private int pointerId = PanelManager.NON_EXISTING_TOUCH; 133 | 134 | private void Awake() 135 | { 136 | m_minSize = new Vector2( 100f, 100f ); 137 | Internal = new InternalSettings( this ); 138 | 139 | iconHolder.preserveAspect = true; 140 | 141 | closeButton.onClick.AddListener( () => PanelNotificationCenter.Internal.TabClosed( this ) ); 142 | } 143 | 144 | private void Start() 145 | { 146 | if( string.IsNullOrEmpty( m_id ) ) 147 | ID = System.Guid.NewGuid().ToString(); 148 | } 149 | 150 | private void OnEnable() 151 | { 152 | pointerId = PanelManager.NON_EXISTING_TOUCH; 153 | } 154 | 155 | private void OnDestroy() 156 | { 157 | PanelNotificationCenter.Internal.TabIDChanged( this, m_id, null ); 158 | } 159 | 160 | public void AttachTo( Panel panel, int tabIndex = -1 ) 161 | { 162 | panel.AddTab( Content, tabIndex ); 163 | } 164 | 165 | public Panel Detach() 166 | { 167 | return m_panel.DetachTab( this ); 168 | } 169 | 170 | public void Destroy() 171 | { 172 | m_panel.RemoveTab( this ); 173 | } 174 | 175 | private void SetActive( bool activeState ) 176 | { 177 | if( !Content ) 178 | m_panel.Internal.RemoveTab( m_panel.GetTabIndex( this ), true ); 179 | else 180 | { 181 | if( activeState ) 182 | { 183 | background.color = m_panel.TabSelectedColor; 184 | nameHolder.color = m_panel.TabSelectedTextColor; 185 | } 186 | else 187 | { 188 | background.color = m_panel.TabNormalColor; 189 | nameHolder.color = m_panel.TabNormalTextColor; 190 | } 191 | 192 | Content.gameObject.SetActive( activeState ); 193 | } 194 | } 195 | 196 | void IPointerClickHandler.OnPointerClick( PointerEventData eventData ) 197 | { 198 | if( !Content ) 199 | m_panel.Internal.RemoveTab( m_panel.GetTabIndex( this ), true ); 200 | else 201 | m_panel.ActiveTab = m_panel.GetTabIndex( this ); 202 | } 203 | 204 | void IBeginDragHandler.OnBeginDrag( PointerEventData eventData ) 205 | { 206 | // Cancel drag event if panel is already being dragged by another pointer, 207 | // or PanelManager does not want the panel to be dragged at that moment 208 | if( !PanelManager.Instance.OnBeginPanelTabTranslate( this, eventData ) ) 209 | { 210 | eventData.pointerDrag = null; 211 | return; 212 | } 213 | 214 | pointerId = eventData.pointerId; 215 | 216 | background.color = m_panel.TabDetachingColor; 217 | nameHolder.color = m_panel.TabDetachingTextColor; 218 | 219 | PanelNotificationCenter.Internal.TabDragStateChanged( this, true ); 220 | } 221 | 222 | void IDragHandler.OnDrag( PointerEventData eventData ) 223 | { 224 | if( eventData.pointerId != pointerId ) 225 | { 226 | eventData.pointerDrag = null; 227 | return; 228 | } 229 | 230 | PanelManager.Instance.OnPanelTabTranslate( this, eventData ); 231 | } 232 | 233 | void IEndDragHandler.OnEndDrag( PointerEventData eventData ) 234 | { 235 | if( eventData.pointerId != pointerId ) 236 | return; 237 | 238 | pointerId = PanelManager.NON_EXISTING_TOUCH; 239 | ResetBackgroundColor(); 240 | 241 | PanelManager.Instance.OnEndPanelTabTranslate( this, eventData ); 242 | PanelNotificationCenter.Internal.TabDragStateChanged( this, false ); 243 | } 244 | 245 | private void ResetBackgroundColor() 246 | { 247 | if( m_panel.ActiveTab == m_panel.GetTabIndex( this ) ) 248 | { 249 | background.color = m_panel.TabSelectedColor; 250 | nameHolder.color = m_panel.TabSelectedTextColor; 251 | } 252 | else 253 | { 254 | background.color = m_panel.TabNormalColor; 255 | nameHolder.color = m_panel.TabNormalTextColor; 256 | } 257 | } 258 | } 259 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelTab.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 37df190a5f116af4d978c253e5f06d63 3 | timeCreated: 1503929790 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelUtils.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace DynamicPanels 4 | { 5 | public static class PanelUtils 6 | { 7 | internal static class Internal 8 | { 9 | public static Panel CreatePanel( RectTransform content, DynamicPanelsCanvas canvas ) 10 | { 11 | bool canvasWasNull = canvas == null; 12 | if( canvasWasNull ) 13 | { 14 | if( content != null ) 15 | canvas = content.GetComponentInParent(); 16 | 17 | if( canvas == null ) 18 | { 19 | #if UNITY_2022_3_OR_NEWER 20 | canvas = Object.FindAnyObjectByType(); 21 | #else 22 | canvas = Object.FindObjectOfType(); 23 | #endif 24 | if( !canvas ) 25 | { 26 | Debug.LogError( "Panels require a DynamicPanelsCanvas!" ); 27 | return null; 28 | } 29 | } 30 | } 31 | 32 | Panel result = null; 33 | if( content != null ) 34 | { 35 | PanelTab currentTab = GetAssociatedTab( content ); 36 | if( currentTab != null ) 37 | result = currentTab.Panel; 38 | } 39 | 40 | if( result == null ) 41 | { 42 | result = (Panel) Object.Instantiate( Resources.Load( "DynamicPanel" ), canvas.RectTransform, false ); 43 | result.gameObject.name = "DynamicPanel"; 44 | result.RectTransform.SetAsLastSibling(); 45 | 46 | if( content != null ) 47 | { 48 | Rect contentRect = content.rect; 49 | 50 | result.RectTransform.anchoredPosition = (Vector2) canvas.RectTransform.InverseTransformPoint( content.TransformPoint( contentRect.position ) ) + canvas.Size * 0.5f; 51 | result.FloatingSize = contentRect.size; 52 | } 53 | } 54 | else if( result.Canvas != canvas && !canvasWasNull ) 55 | canvas.UnanchoredPanelGroup.AddElement( result ); 56 | 57 | if( content != null ) 58 | result.AddTab( content ); 59 | 60 | return result; 61 | } 62 | } 63 | 64 | public static Panel CreatePanelFor( RectTransform content, DynamicPanelsCanvas canvas ) 65 | { 66 | if( !content ) 67 | { 68 | Debug.LogError( "Content is null!" ); 69 | return null; 70 | } 71 | 72 | return Internal.CreatePanel( content, canvas ); 73 | } 74 | 75 | public static PanelTab GetAssociatedTab( RectTransform content ) 76 | { 77 | if( !content ) 78 | { 79 | Debug.LogError( "Content is null!" ); 80 | return null; 81 | } 82 | 83 | if( content.parent == null || content.parent.parent == null ) 84 | return null; 85 | 86 | Panel panel = content.parent.parent.GetComponent(); 87 | if( panel == null ) 88 | return null; 89 | 90 | return panel.GetTab( content ); 91 | } 92 | 93 | public static Direction Opposite( this Direction direction ) 94 | { 95 | return (Direction) ( ( (int) direction + 2 ) % 4 ); 96 | } 97 | 98 | public static bool IsNull( this IPanelGroupElement element ) 99 | { 100 | return element == null || element.Equals( null ); 101 | } 102 | 103 | // Credit: https://github.com/Unity-Technologies/UnityCsReference/blob/4fc5eb0fb2c7f5fb09f990fc99f162c8d06d9570/Editor/Mono/Inspector/RectTransformEditor.cs#L1259 104 | public static void ChangePivotWithoutAffectingPosition( this RectTransform rectTransform, Vector2 pivot ) 105 | { 106 | if( rectTransform.pivot == pivot ) 107 | return; 108 | 109 | Vector3 cornerBefore; 110 | Vector3[] s_Corners = new Vector3[4]; 111 | rectTransform.GetWorldCorners( s_Corners ); 112 | if( rectTransform.parent ) 113 | cornerBefore = rectTransform.parent.InverseTransformPoint( s_Corners[0] ); 114 | else 115 | cornerBefore = s_Corners[0]; 116 | 117 | rectTransform.pivot = pivot; 118 | 119 | Vector3 cornerAfter; 120 | rectTransform.GetWorldCorners( s_Corners ); 121 | if( rectTransform.parent ) 122 | cornerAfter = rectTransform.parent.InverseTransformPoint( s_Corners[0] ); 123 | else 124 | cornerAfter = s_Corners[0]; 125 | 126 | Vector3 cornerOffset = cornerAfter - cornerBefore; 127 | rectTransform.anchoredPosition -= (Vector2) cornerOffset; 128 | 129 | Vector3 pos = rectTransform.transform.position; 130 | pos.z -= cornerOffset.z; 131 | rectTransform.transform.position = pos; 132 | } 133 | } 134 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Helpers/PanelUtils.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6a8b928efd02d8c499f887910fdaa503 3 | timeCreated: 1504774603 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/Panel.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d12fb16f32dbe264e825a678eff38a90 3 | timeCreated: 1503911411 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/PanelManager.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | using UnityEngine.EventSystems; 4 | #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER 5 | using UnityEngine.InputSystem; 6 | #endif 7 | 8 | namespace DynamicPanels 9 | { 10 | public enum Direction { None = -1, Left = 0, Top = 1, Right = 2, Bottom = 3 }; 11 | 12 | [DisallowMultipleComponent] 13 | public class PanelManager : MonoBehaviour 14 | { 15 | public const int NON_EXISTING_TOUCH = -98765; 16 | private const float PANEL_TABS_VALIDATE_INTERVAL = 5f; 17 | 18 | private static PanelManager m_instance; 19 | public static PanelManager Instance 20 | { 21 | get 22 | { 23 | if( m_instance == null ) 24 | m_instance = new GameObject( "PanelManager" ).AddComponent(); 25 | 26 | return m_instance; 27 | } 28 | } 29 | 30 | private List canvases = new List( 8 ); 31 | private List panels = new List( 32 ); 32 | 33 | private Panel draggedPanel = null; 34 | private AnchorZoneBase hoveredAnchorZone = null; 35 | 36 | private RectTransform previewPanel = null; 37 | private DynamicPanelsCanvas previewPanelCanvas; 38 | 39 | private float nextPanelValidationTime; 40 | private PointerEventData nullPointerEventData; 41 | 42 | private void Awake() 43 | { 44 | if( m_instance == null ) 45 | m_instance = this; 46 | else if( this != m_instance ) 47 | { 48 | Destroy( this ); 49 | return; 50 | } 51 | 52 | InitializePreviewPanel(); 53 | 54 | DontDestroyOnLoad( gameObject ); 55 | DontDestroyOnLoad( previewPanel.gameObject ); 56 | 57 | nextPanelValidationTime = Time.realtimeSinceStartup + PANEL_TABS_VALIDATE_INTERVAL; 58 | nullPointerEventData = new PointerEventData( null ); 59 | 60 | #if UNITY_2018_1_OR_NEWER 61 | // OnApplicationQuit isn't reliable on some Unity versions when Application.wantsToQuit is used; Application.quitting is the only reliable solution on those versions 62 | // https://issuetracker.unity3d.com/issues/onapplicationquit-method-is-called-before-application-dot-wantstoquit-event-is-raised 63 | Application.quitting -= OnApplicationQuitting; 64 | Application.quitting += OnApplicationQuitting; 65 | #endif 66 | } 67 | 68 | #if UNITY_2018_1_OR_NEWER 69 | private void OnDestroy() 70 | { 71 | Application.quitting -= OnApplicationQuitting; 72 | } 73 | #endif 74 | 75 | #if UNITY_2018_1_OR_NEWER 76 | private void OnApplicationQuitting() 77 | #else 78 | private void OnApplicationQuit() 79 | #endif 80 | { 81 | for( int i = 0; i < panels.Count; i++ ) 82 | panels[i].Internal.OnApplicationQuit(); 83 | 84 | for( int i = 0; i < canvases.Count; i++ ) 85 | canvases[i].Internal.OnApplicationQuit(); 86 | } 87 | 88 | private void Update() 89 | { 90 | if( draggedPanel == null ) 91 | { 92 | #if ENABLE_INPUT_SYSTEM && !ENABLE_LEGACY_INPUT_MANAGER 93 | if( Pointer.current != null ) 94 | { 95 | if( Pointer.current.press.wasPressedThisFrame ) 96 | BringClickedPanelToForward( Pointer.current.position.ReadValue() ); 97 | else if( Mouse.current != null ) 98 | { 99 | if( Mouse.current.rightButton.wasPressedThisFrame || Mouse.current.middleButton.wasPressedThisFrame ) 100 | BringClickedPanelToForward( Mouse.current.position.ReadValue() ); 101 | } 102 | } 103 | #else 104 | if( Input.touchCount == 0 ) 105 | { 106 | if( Input.GetMouseButtonDown( 0 ) || Input.GetMouseButtonDown( 1 ) || Input.GetMouseButtonDown( 2 ) ) 107 | BringClickedPanelToForward( Input.mousePosition ); 108 | } 109 | else 110 | { 111 | for( int i = 0; i < Input.touchCount; i++ ) 112 | { 113 | Touch touch = Input.GetTouch( i ); 114 | if( touch.phase == TouchPhase.Began ) 115 | BringClickedPanelToForward( touch.position ); 116 | } 117 | } 118 | #endif 119 | } 120 | 121 | if( Time.realtimeSinceStartup >= nextPanelValidationTime ) 122 | { 123 | for( int i = 0; i < panels.Count; i++ ) 124 | panels[i].Internal.ValidateTabs(); 125 | 126 | nextPanelValidationTime = Time.realtimeSinceStartup + PANEL_TABS_VALIDATE_INTERVAL; 127 | } 128 | } 129 | 130 | public void RegisterCanvas( DynamicPanelsCanvas canvas ) 131 | { 132 | if( !canvases.Contains( canvas ) ) 133 | canvases.Add( canvas ); 134 | } 135 | 136 | public void UnregisterCanvas( DynamicPanelsCanvas canvas ) 137 | { 138 | canvases.Remove( canvas ); 139 | StopCanvasOperations( canvas ); 140 | 141 | if( previewPanelCanvas == canvas ) 142 | previewPanelCanvas = draggedPanel != null ? draggedPanel.Canvas : null; 143 | 144 | if( previewPanel.parent == canvas.RectTransform ) 145 | previewPanel.SetParent( null, false ); 146 | } 147 | 148 | public void RegisterPanel( Panel panel ) 149 | { 150 | if( !panels.Contains( panel ) ) 151 | { 152 | panels.Add( panel ); 153 | panel.GetComponentInParent().UnanchoredPanelGroup.AddElement( panel ); 154 | } 155 | } 156 | 157 | public void UnregisterPanel( Panel panel ) 158 | { 159 | if( draggedPanel == panel ) 160 | draggedPanel = null; 161 | 162 | panels.Remove( panel ); 163 | panel.Group.Internal.SetDirty(); 164 | } 165 | 166 | public void AnchorPanel( IPanelGroupElement source, DynamicPanelsCanvas canvas, Direction anchorDirection ) 167 | { 168 | PanelGroup rootGroup = canvas.RootPanelGroup; 169 | PanelGroup tempGroup = new PanelGroup( canvas, Direction.Right ); 170 | for( int i = 0; i < rootGroup.Count; i++ ) 171 | { 172 | if( rootGroup[i].Group == rootGroup ) 173 | tempGroup.AddElement( rootGroup[i] ); 174 | } 175 | 176 | rootGroup.AddElement( tempGroup ); 177 | AnchorPanel( source, tempGroup, anchorDirection ); 178 | } 179 | 180 | public void AnchorPanel( IPanelGroupElement source, IPanelGroupElement anchor, Direction anchorDirection ) 181 | { 182 | PanelGroup group = anchor.Group; 183 | if( group is UnanchoredPanelGroup ) 184 | { 185 | Debug.LogError( "Can not anchor to an unanchored panel!" ); 186 | return; 187 | } 188 | 189 | Vector2 size; 190 | Panel panel = source as Panel; 191 | if( panel != null ) 192 | size = panel.IsDocked ? panel.FloatingSize : panel.Size; 193 | else 194 | { 195 | ( (PanelGroup) source ).Internal.UpdateLayout(); 196 | size = source.Size; 197 | } 198 | 199 | // Fill the whole anchored area in order not to break other elements' sizes on layout update 200 | if( anchorDirection == Direction.Left || anchorDirection == Direction.Right ) 201 | { 202 | if( anchor.Size.y > 0f ) 203 | size.y = anchor.Size.y; 204 | } 205 | else 206 | { 207 | if( anchor.Size.x > 0f ) 208 | size.x = anchor.Size.x; 209 | } 210 | 211 | if( panel != null ) 212 | panel.RectTransform.sizeDelta = size; 213 | else 214 | ( (PanelGroup) source ).Internal.UpdateBounds( source.Position, size ); 215 | 216 | bool addElementAfter = anchorDirection == Direction.Right || anchorDirection == Direction.Top; 217 | if( group.IsInSameDirection( anchorDirection ) ) 218 | { 219 | if( addElementAfter ) 220 | group.AddElementAfter( anchor, source ); 221 | else 222 | group.AddElementBefore( anchor, source ); 223 | } 224 | else 225 | { 226 | IPanelGroupElement element1, element2; 227 | if( addElementAfter ) 228 | { 229 | element1 = anchor; 230 | element2 = source; 231 | } 232 | else 233 | { 234 | element1 = source; 235 | element2 = anchor; 236 | } 237 | 238 | PanelGroup newGroup = new PanelGroup( anchor.Canvas, anchorDirection ); 239 | newGroup.AddElement( element1 ); 240 | newGroup.AddElement( element2 ); 241 | 242 | group.Internal.ReplaceElement( anchor, newGroup ); 243 | } 244 | 245 | if( panel != null ) 246 | { 247 | if( draggedPanel == panel ) 248 | draggedPanel = null; 249 | 250 | panel.RectTransform.SetAsFirstSibling(); 251 | 252 | if( panel.Internal.ContentScrollRect != null ) 253 | panel.Internal.ContentScrollRect.OnDrag( nullPointerEventData ); 254 | } 255 | } 256 | 257 | public void DetachPanel( Panel panel ) 258 | { 259 | if( draggedPanel == panel ) 260 | draggedPanel = null; 261 | 262 | if( panel.IsDocked ) 263 | { 264 | panel.Canvas.UnanchoredPanelGroup.AddElement( panel ); 265 | panel.RectTransform.SetAsLastSibling(); 266 | panel.RectTransform.sizeDelta = panel.FloatingSize; 267 | 268 | if( panel.Internal.ContentScrollRect != null ) 269 | panel.Internal.ContentScrollRect.OnDrag( nullPointerEventData ); 270 | } 271 | } 272 | 273 | public Panel DetachPanelTab( Panel panel, int tabIndex ) 274 | { 275 | if( tabIndex >= 0 && tabIndex < panel.NumberOfTabs ) 276 | { 277 | if( panel.NumberOfTabs == 1 ) 278 | { 279 | DetachPanel( panel ); 280 | return panel; 281 | } 282 | else 283 | { 284 | Panel newPanel = PanelUtils.Internal.CreatePanel( null, panel.Canvas ); 285 | newPanel.AddTab( panel[tabIndex].Content ); 286 | newPanel.FloatingSize = panel.FloatingSize; 287 | 288 | if( newPanel.Internal.ContentScrollRect != null ) 289 | newPanel.Internal.ContentScrollRect.OnDrag( nullPointerEventData ); 290 | 291 | return newPanel; 292 | } 293 | } 294 | 295 | return null; 296 | } 297 | 298 | private void BringClickedPanelToForward( Vector2 screenPoint ) 299 | { 300 | for( int i = 0; i < canvases.Count; i++ ) 301 | { 302 | if( !canvases[i].gameObject.activeInHierarchy ) 303 | continue; 304 | 305 | Camera worldCamera = canvases[i].Internal.worldCamera; 306 | if( RectTransformUtility.RectangleContainsScreenPoint( canvases[i].RectTransform, screenPoint, worldCamera ) ) 307 | { 308 | RectTransform panelAtTop = null; 309 | for( int j = 0; j < panels.Count; j++ ) 310 | { 311 | if( panels[j].IsDocked || panels[j].Internal.IsDummy ) 312 | continue; 313 | 314 | if( panels[j].Canvas == canvases[i] && RectTransformUtility.RectangleContainsScreenPoint( panels[j].Internal.HighlightTransform, screenPoint, worldCamera ) ) 315 | { 316 | if( panelAtTop == null || panels[j].RectTransform.GetSiblingIndex() > panelAtTop.GetSiblingIndex() ) 317 | panelAtTop = panels[j].RectTransform; 318 | } 319 | } 320 | 321 | if( panelAtTop != null ) 322 | { 323 | panelAtTop.SetAsLastSibling(); 324 | return; 325 | } 326 | } 327 | } 328 | } 329 | 330 | public void StopCanvasOperations( DynamicPanelsCanvas canvas ) 331 | { 332 | CancelDraggingPanel(); 333 | 334 | for( int i = 0; i < panels.Count; i++ ) 335 | { 336 | if( panels[i].Canvas == canvas ) 337 | panels[i].Internal.Stop(); 338 | } 339 | } 340 | 341 | public void CancelDraggingPanel() 342 | { 343 | if( draggedPanel != null ) 344 | { 345 | if( draggedPanel.RectTransform.parent != draggedPanel.Canvas.RectTransform ) 346 | { 347 | draggedPanel.RectTransform.SetParent( draggedPanel.Canvas.RectTransform, false ); 348 | draggedPanel.RectTransform.SetAsLastSibling(); 349 | } 350 | 351 | AnchorZonesSetActive( false ); 352 | 353 | UnanchoredPanelGroup unanchoredGroup = draggedPanel.Group as UnanchoredPanelGroup; 354 | if( unanchoredGroup != null ) 355 | unanchoredGroup.RestrictPanelToBounds( draggedPanel ); 356 | 357 | draggedPanel.Internal.Stop(); 358 | draggedPanel = null; 359 | } 360 | 361 | hoveredAnchorZone = null; 362 | 363 | if( previewPanel.gameObject.activeSelf ) 364 | previewPanel.gameObject.SetActive( false ); 365 | } 366 | 367 | public void OnPointerEnteredCanvas( DynamicPanelsCanvas canvas, PointerEventData pointer ) 368 | { 369 | if( draggedPanel != null && pointer.pointerDrag != null ) 370 | { 371 | PanelHeader header = pointer.pointerDrag.GetComponent(); 372 | if( header != null ) 373 | { 374 | if( header.Panel == draggedPanel && header.Panel.RectTransform.parent != canvas.RectTransform ) 375 | { 376 | previewPanelCanvas = canvas; 377 | 378 | header.Panel.RectTransform.SetParent( canvas.RectTransform, false ); 379 | header.Panel.RectTransform.SetAsLastSibling(); 380 | } 381 | } 382 | else 383 | { 384 | PanelTab tab = pointer.pointerDrag.GetComponent(); 385 | if( tab != null ) 386 | { 387 | if( tab.Panel == draggedPanel && previewPanel.parent != canvas.RectTransform ) 388 | { 389 | previewPanelCanvas = canvas; 390 | 391 | if( hoveredAnchorZone && hoveredAnchorZone.Panel.Canvas != canvas ) 392 | hoveredAnchorZone.OnPointerExit( pointer ); 393 | 394 | previewPanel.SetParent( canvas.RectTransform, false ); 395 | previewPanel.SetAsLastSibling(); 396 | } 397 | } 398 | } 399 | } 400 | } 401 | 402 | #region Panel Header Drag Callbacks 403 | public bool OnBeginPanelTranslate( Panel panel ) 404 | { 405 | if( panel.IsDocked ) 406 | return false; 407 | 408 | if( draggedPanel != null ) 409 | CancelDraggingPanel(); 410 | 411 | draggedPanel = panel; 412 | previewPanelCanvas = draggedPanel.Canvas; 413 | 414 | for( int i = 0; i < canvases.Count; i++ ) 415 | canvases[i].Internal.ReceiveRaycasts( true ); 416 | 417 | return true; 418 | } 419 | 420 | public void OnPanelTranslate( PanelHeader panelHeader, PointerEventData draggingPointer ) 421 | { 422 | if( draggedPanel == panelHeader.Panel ) 423 | { 424 | Vector2 touchPos; 425 | RectTransformUtility.ScreenPointToLocalPointInRectangle( draggedPanel.RectTransform, draggingPointer.position, previewPanelCanvas.Internal.worldCamera, out touchPos ); 426 | 427 | draggedPanel.RectTransform.anchoredPosition += touchPos - panelHeader.InitialTouchPos; 428 | } 429 | } 430 | 431 | public void OnEndPanelTranslate( Panel panel ) 432 | { 433 | if( draggedPanel == panel ) 434 | { 435 | if( draggedPanel.RectTransform.parent != draggedPanel.Canvas.RectTransform ) 436 | draggedPanel.RectTransform.parent.GetComponent().UnanchoredPanelGroup.AddElement( draggedPanel ); 437 | 438 | for( int i = 0; i < canvases.Count; i++ ) 439 | canvases[i].Internal.ReceiveRaycasts( false ); 440 | 441 | draggedPanel = null; 442 | ( (UnanchoredPanelGroup) panel.Group ).RestrictPanelToBounds( panel ); 443 | } 444 | } 445 | #endregion 446 | 447 | #region Panel Tab Drag Callbacks 448 | public bool OnBeginPanelTabTranslate( PanelTab panelTab, PointerEventData draggingPointer ) 449 | { 450 | if( draggedPanel != null ) 451 | CancelDraggingPanel(); 452 | 453 | if( panelTab.Panel.NumberOfTabs == 1 && panelTab.Panel.Canvas.PreventDetachingLastDockedPanel && panelTab.Panel.Canvas.Internal.IsLastDockedPanel( panelTab.Panel ) ) 454 | return false; 455 | 456 | draggedPanel = panelTab.Panel; 457 | 458 | if( !draggedPanel.IsDocked ) 459 | draggedPanel.FloatingSize = draggedPanel.Size; 460 | 461 | AnchorZonesSetActive( true ); 462 | 463 | if( draggedPanel.NumberOfTabs <= 1 ) 464 | draggedPanel.Internal.PanelAnchorZone.SetActive( false ); 465 | 466 | if( RectTransformUtility.RectangleContainsScreenPoint( draggedPanel.Internal.HeaderAnchorZone.RectTransform, draggingPointer.position, draggedPanel.Canvas.Internal.worldCamera ) ) 467 | { 468 | draggedPanel.Internal.HeaderAnchorZone.OnPointerEnter( draggingPointer ); 469 | draggingPointer.pointerEnter = draggedPanel.Internal.HeaderAnchorZone.gameObject; 470 | } 471 | 472 | previewPanelCanvas = draggedPanel.Canvas; 473 | if( previewPanel.parent != previewPanelCanvas.RectTransform ) 474 | previewPanel.SetParent( previewPanelCanvas.RectTransform, false ); 475 | 476 | previewPanel.gameObject.SetActive( true ); 477 | previewPanel.SetAsLastSibling(); 478 | 479 | return true; 480 | } 481 | 482 | public void OnPanelTabTranslate( PanelTab panelTab, PointerEventData draggingPointer ) 483 | { 484 | if( draggedPanel == panelTab.Panel ) 485 | { 486 | Rect previewRect; 487 | if( hoveredAnchorZone != null && hoveredAnchorZone.GetAnchoredPreviewRectangleAt( draggingPointer, out previewRect ) ) 488 | { 489 | previewPanel.anchoredPosition = previewRect.position; 490 | previewPanel.sizeDelta = previewRect.size; 491 | } 492 | else 493 | { 494 | Vector2 position; 495 | RectTransformUtility.ScreenPointToLocalPointInRectangle( previewPanelCanvas.RectTransform, draggingPointer.position, previewPanelCanvas.Internal.worldCamera, out position ); 496 | previewPanel.anchoredPosition = position; 497 | previewPanel.sizeDelta = panelTab.Panel.FloatingSize; 498 | } 499 | } 500 | } 501 | 502 | public void OnEndPanelTabTranslate( PanelTab panelTab, PointerEventData draggingPointer ) 503 | { 504 | if( draggedPanel == panelTab.Panel ) 505 | { 506 | AnchorZoneBase targetAnchor = hoveredAnchorZone; 507 | if( hoveredAnchorZone != null ) 508 | hoveredAnchorZone.OnPointerExit( draggingPointer ); 509 | 510 | AnchorZonesSetActive( false ); 511 | 512 | if( targetAnchor == null || !targetAnchor.Execute( panelTab, draggingPointer ) ) 513 | { 514 | Panel detachedPanel = DetachPanelTab( draggedPanel, draggedPanel.GetTabIndex( panelTab.Content ) ); 515 | if( detachedPanel.Canvas != previewPanelCanvas ) 516 | { 517 | previewPanelCanvas.UnanchoredPanelGroup.AddElement( detachedPanel ); 518 | detachedPanel.RectTransform.SetAsLastSibling(); 519 | } 520 | 521 | detachedPanel.MoveTo( draggingPointer.position ); 522 | } 523 | 524 | draggedPanel = null; 525 | hoveredAnchorZone = null; 526 | previewPanel.gameObject.SetActive( false ); 527 | } 528 | } 529 | #endregion 530 | 531 | #region Preview Panel Handlers 532 | public bool AnchorPreviewPanelTo( AnchorZoneBase anchorZone ) 533 | { 534 | if( hoveredAnchorZone != null || draggedPanel == null ) 535 | return false; 536 | 537 | hoveredAnchorZone = anchorZone; 538 | return true; 539 | } 540 | 541 | public void StopAnchorPreviewPanelTo( AnchorZoneBase anchorZone ) 542 | { 543 | if( hoveredAnchorZone == anchorZone ) 544 | hoveredAnchorZone = null; 545 | } 546 | #endregion 547 | 548 | private void AnchorZonesSetActive( bool value ) 549 | { 550 | for( int i = 0; i < panels.Count; i++ ) 551 | panels[i].Internal.AnchorZonesSetActive( value ); 552 | 553 | for( int i = 0; i < canvases.Count; i++ ) 554 | { 555 | canvases[i].Internal.AnchorZonesSetActive( value ); 556 | canvases[i].Internal.ReceiveRaycasts( value ); 557 | } 558 | } 559 | 560 | private void InitializePreviewPanel() 561 | { 562 | RectTransform previewPanel = Instantiate( Resources.Load( "DynamicPanelPreview" ) ); 563 | previewPanel.gameObject.name = "DraggedPanelPreview"; 564 | 565 | previewPanel.anchorMin = new Vector2( 0.5f, 0.5f ); 566 | previewPanel.anchorMax = new Vector2( 0.5f, 0.5f ); 567 | previewPanel.pivot = new Vector2( 0.5f, 0.5f ); 568 | 569 | previewPanel.gameObject.SetActive( false ); 570 | 571 | this.previewPanel = previewPanel; 572 | } 573 | } 574 | } -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Scripts/PanelManager.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c4e929e4f7196f0469eff9e6b709877d 3 | timeCreated: 1503995323 4 | licenseType: Pro 5 | MonoImporter: 6 | serializedVersion: 2 7 | defaultReferences: [] 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 022c852bc988849428da3536bc06773d 3 | folderAsset: yes 4 | timeCreated: 1506292608 5 | licenseType: Free 6 | DefaultImporter: 7 | userData: 8 | assetBundleName: 9 | assetBundleVariant: 10 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites/CloseButton.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Sprites/CloseButton.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites/CloseButton.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20c417e04b8c35f4091523662474a6c4 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 5 33 | maxTextureSize: 32 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 1 66 | cookieLightType: 1 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 1 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 1 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 1 104 | - serializedVersion: 3 105 | buildTarget: WebGL 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 1 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: DynamicPanels 131 | pSDRemoveMatte: 1 132 | pSDShowRemoveMatteOption: 1 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites/PanelBackground.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Sprites/PanelBackground.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites/PanelBackground.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7143c7559b82cd14da677a36b3df8d4d 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 6, y: 6, z: 6, w: 6} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 1 66 | cookieLightType: 1 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 1 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 1 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 1 104 | - serializedVersion: 3 105 | buildTarget: WebGL 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 1 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: DynamicPanels 131 | pSDRemoveMatte: 1 132 | pSDShowRemoveMatteOption: 1 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites/PanelTabBackground.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yasirkula/UnityDynamicPanels/f69af3a9cdecb93ee00e28cb8a10e54fd3a9d957/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd -------------------------------------------------------------------------------- /Plugins/DynamicPanels/Sprites/PanelTabBackground.psd.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ef24468435bb0d64296ede4cf9b6cc18 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 12 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 0 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | vTOnly: 0 27 | ignoreMasterTextureLimit: 0 28 | grayScaleToAlpha: 0 29 | generateCubemap: 6 30 | cubemapConvolution: 0 31 | seamlessCubemap: 0 32 | textureFormat: 1 33 | maxTextureSize: 2048 34 | textureSettings: 35 | serializedVersion: 2 36 | filterMode: 1 37 | aniso: 1 38 | mipBias: 0 39 | wrapU: 1 40 | wrapV: 1 41 | wrapW: 1 42 | nPOTScale: 0 43 | lightmap: 0 44 | compressionQuality: 50 45 | spriteMode: 1 46 | spriteExtrude: 1 47 | spriteMeshType: 1 48 | alignment: 0 49 | spritePivot: {x: 0.5, y: 0.5} 50 | spritePixelsToUnits: 100 51 | spriteBorder: {x: 6, y: 6, z: 6, w: 6} 52 | spriteGenerateFallbackPhysicsShape: 1 53 | alphaUsage: 1 54 | alphaIsTransparency: 1 55 | spriteTessellationDetail: -1 56 | textureType: 8 57 | textureShape: 1 58 | singleChannelComponent: 0 59 | flipbookRows: 1 60 | flipbookColumns: 1 61 | maxTextureSizeSet: 0 62 | compressionQualitySet: 0 63 | textureFormatSet: 0 64 | ignorePngGamma: 0 65 | applyGammaDecoding: 1 66 | cookieLightType: 1 67 | platformSettings: 68 | - serializedVersion: 3 69 | buildTarget: DefaultTexturePlatform 70 | maxTextureSize: 2048 71 | resizeAlgorithm: 0 72 | textureFormat: -1 73 | textureCompression: 1 74 | compressionQuality: 50 75 | crunchedCompression: 0 76 | allowsAlphaSplitting: 0 77 | overridden: 0 78 | androidETC2FallbackOverride: 0 79 | forceMaximumCompressionQuality_BC6H_BC7: 1 80 | - serializedVersion: 3 81 | buildTarget: Standalone 82 | maxTextureSize: 2048 83 | resizeAlgorithm: 0 84 | textureFormat: -1 85 | textureCompression: 1 86 | compressionQuality: 50 87 | crunchedCompression: 0 88 | allowsAlphaSplitting: 0 89 | overridden: 0 90 | androidETC2FallbackOverride: 0 91 | forceMaximumCompressionQuality_BC6H_BC7: 1 92 | - serializedVersion: 3 93 | buildTarget: Android 94 | maxTextureSize: 2048 95 | resizeAlgorithm: 0 96 | textureFormat: -1 97 | textureCompression: 1 98 | compressionQuality: 50 99 | crunchedCompression: 0 100 | allowsAlphaSplitting: 0 101 | overridden: 0 102 | androidETC2FallbackOverride: 0 103 | forceMaximumCompressionQuality_BC6H_BC7: 1 104 | - serializedVersion: 3 105 | buildTarget: WebGL 106 | maxTextureSize: 2048 107 | resizeAlgorithm: 0 108 | textureFormat: -1 109 | textureCompression: 1 110 | compressionQuality: 50 111 | crunchedCompression: 0 112 | allowsAlphaSplitting: 0 113 | overridden: 0 114 | androidETC2FallbackOverride: 0 115 | forceMaximumCompressionQuality_BC6H_BC7: 1 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 5e97eb03825dee720800000000000000 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | nameFileIdTable: {} 130 | spritePackingTag: DynamicPanels 131 | pSDRemoveMatte: 1 132 | pSDShowRemoveMatteOption: 1 133 | userData: 134 | assetBundleName: 135 | assetBundleVariant: 136 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.yasirkula.dynamicpanels", 3 | "displayName": "Dynamic Panels", 4 | "version": "1.3.3", 5 | "documentationUrl": "https://github.com/yasirkula/UnityDynamicPanels", 6 | "changelogUrl": "https://github.com/yasirkula/UnityDynamicPanels/releases", 7 | "licensesUrl": "https://github.com/yasirkula/UnityDynamicPanels/blob/master/LICENSE.txt", 8 | "description": "This asset helps you create dynamic panels using Unity's UI system. These panels can be dragged around, resized, docked to canvas edges or to one another and stacked next to each other as separate tabs.", 9 | "hideInEditor": false 10 | } 11 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b6d310720b6c8be47a3ba0356a0b4827 3 | PackageManifestImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------