From beb0119dd54c03d0258a3f5174b7face1bf5b7b0 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 09:28:31 +0700 Subject: [PATCH 01/44] initial wiki sidebar --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/WikiSidebar.cs diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs new file mode 100644 index 0000000000..6d1f520135 --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -0,0 +1,9 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Overlays.Wiki +{ + public class WikiSidebar : OverlaySidebar + { + } +} From 791a9dd33a3a6754170457a9da701f776b4c7958 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 09:29:10 +0700 Subject: [PATCH 02/44] add WikiArticlePage --- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 54 +++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/WikiArticlePage.cs diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs new file mode 100644 index 0000000000..c41ab8b250 --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -0,0 +1,54 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Overlays.Wiki.Markdown; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiArticlePage : GridContainer + { + public Container SidebarContainer { get; } + + public WikiArticlePage(string currentPath, string markdown) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }; + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }; + Content = new[] + { + new Drawable[] + { + SidebarContainer = new Container + { + AutoSizeAxes = Axes.X, + Child = new WikiSidebar(), + }, + new WikiMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + CurrentPath = currentPath, + Text = markdown, + DocumentMargin = new MarginPadding(0), + DocumentPadding = new MarginPadding + { + Vertical = 20, + Left = 30, + Right = 50, + }, + } + }, + }; + } + } +} From 458910b7446e618ef132a1e5b0cf4b2e92d8b519 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 09:29:36 +0700 Subject: [PATCH 03/44] use WikiArticlePage in WikiOverlay --- osu.Game/Overlays/WikiOverlay.cs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index c5ba0eed66..4cfbbbbfe4 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using System.Threading; using osu.Framework.Allocation; @@ -10,7 +11,6 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Wiki; -using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays { @@ -31,6 +31,8 @@ namespace osu.Game.Overlays private bool displayUpdateRequired = true; + private WikiArticlePage articlePage; + public WikiOverlay() : base(OverlayColourScheme.Orange, false) { @@ -82,6 +84,17 @@ namespace osu.Game.Overlays }, (cancellationToken = new CancellationTokenSource()).Token); } + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (articlePage != null) + { + articlePage.SidebarContainer.Height = DrawHeight; + articlePage.SidebarContainer.Y = Math.Clamp(ScrollFlow.Current - Header.DrawHeight, 0, Math.Max(ScrollFlow.ScrollContent.DrawHeight - DrawHeight - Header.DrawHeight, 0)); + } + } + private void onPathChanged(ValueChangedEvent e) { cancellationToken?.Cancel(); @@ -115,20 +128,7 @@ namespace osu.Game.Overlays } else { - LoadDisplay(new WikiMarkdownContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - CurrentPath = $@"{api.WebsiteRootUrl}/wiki/{path.Value}/", - Text = response.Markdown, - DocumentMargin = new MarginPadding(0), - DocumentPadding = new MarginPadding - { - Vertical = 20, - Left = 30, - Right = 50, - }, - }); + LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/{path.Value}/", response.Markdown)); } } From 34379b953af958c1a8ac2634cf1bdf9bb3fb72fb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 09:36:21 +0700 Subject: [PATCH 04/44] change test scene response --- osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 4d09ed21dc..3506d459ce 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Online public void TestArticlePage() { setUpWikiResponse(responseArticlePage); - AddStep("Show Article Page", () => wiki.ShowPage("Interface")); + AddStep("Show Article Page", () => wiki.ShowPage("Article_styling_criteria/Formatting")); } [Test] @@ -69,16 +69,16 @@ namespace osu.Game.Tests.Visual.Online "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n", }; - // From https://osu.ppy.sh/api/v2/wiki/en/Interface + // From https://osu.ppy.sh/api/v2/wiki/en/Article_styling_criteria/Formatting private APIWikiPage responseArticlePage => new APIWikiPage { - Title = "Interface", + Title = "Formatting", Layout = "markdown_page", - Path = "Interface", + Path = "Article_styling_criteria/Formatting", Locale = "en", - Subtitle = null, + Subtitle = "Article styling criteria", Markdown = - "# Interface\n\n![](img/intro-screen.jpg \"Introduction screen\")\n\n## Main Menu\n\n![](img/main-menu.jpg \"Main Menu\")\n\nThe [osu!cookie](/wiki/Glossary#cookie) \\[1\\] pulses according to the [BPM](/wiki/Beatmapping/Beats_per_minute) of any song currently playing on the main menu. In addition, bars will extend out of the osu!cookie in accordance to the song's volume. If no song is playing, it pulses at a slow 60 BPM. The elements of the main menu are as follows:\n\n- \\[2\\] Click Play (`P`) or the logo to switch to the Solo mode song selection screen.\n- \\[3\\] Click Edit (`E`) to open the Editor mode song selection screen.\n- \\[4\\] Click Options (`O`) to go to the Options screen.\n- \\[5\\] Click Exit (`Esc`) to exit osu!.\n- \\[6\\] A random useful tip is displayed below the menu.\n- \\[7\\] In the lower-left is a link to the osu! website, as well as copyright information.\n- \\[8\\] Connection result to [Bancho](/wiki/Glossary#bancho)! In this picture it is not shown, but the connection result looks like a chain link.\n- \\[9\\] In the bottom right are the chat controls for the extended [chat window](/wiki/Chat_Console) (called \"Player List\" here) and the regular chat window (`F9` & `F8`, respectively).\n- \\[10\\] In the upper right is the osu! jukebox which plays the songs in random order. The top shows the song currently playing. The buttons, from left to right, do as follows:\n - Previous Track\n - Play\n - Pause\n - Stop (the difference between Play and Stop is that Stop will reset the song to the beginning, while Pause simply pauses it)\n - Next Track\n - View Song Info. This toggles the top bar showing the song info between being permanent and temporary. When permanent, the info bar will stay visible until it fades out with the rest of the UI. When temporary, it will disappear a little while after a song has been chosen. It will stay hidden until it is toggled again, or another song plays.\n- \\[11\\] The number of beatmaps you have available, how long your osu!client has been running, and your system clock.\n- \\[12\\] Your profile, click on it to display the User Options (see below).\n\n## User Options\n\n![](img/user-options.jpg \"User Options\")\n\nAccess this screen by clicking your profile at the top left of the main menu. You cannot access the Chat Consoles while viewing the user option screen. You can select any item by pressing the corresponding number on the option:\n\n1. `View Profile`: Opens up your profile page in your default web browser.\n2. `Sign Out`: Sign out of your account (after signing out, the [Options](/wiki/Options) sidebar will prompt you to sign in).\n3. `Change Avatar`: Open up the edit avatar page in your default web browser.\n4. `Close`: Close this dialog\n\n## Play Menu\n\n![](img/play-menu.jpg \"Play Menu\")\n\n- Click `Solo` (`P`) to play alone.\n- Click `Multi` (`M`) to play with other people. You will be directed to the [Multi](/wiki/Multi) Lobby (see below).\n- Click `Back` to return to the main menu.\n\n## Multi Lobby\n\n*Main page: [Multi](/wiki/Multi)*\n\n![](img/multi-lobby.jpg \"Multi Lobby\")\n\n![](img/multi-room.jpg \"Multi Host\")\n\n1. Your rank in the match. This is also shown next to your name.\n2. Your profile information.\n3. The jukebox.\n4. Player list - displays player names, their rank (host or player), their [mods](/wiki/Game_modifier) activated (if any, see \\#7), their osu! ranking, and their team (if applicable).\n5. The name of the match and the password settings.\n6. The beatmap selected. It shows the beatmap as it would in the solo song selection screen.\n7. The [mods](/wiki/Game_modifier) that you have activated (see #12), as well as the option to select them. The option marked \"Free Mods\" toggles whether or not players can select their own mods. If yes, they can pick any combination of mods *except for speed-altering mods like [Double Time](/wiki/Game_modifier/Double_Time)*. If no, the host decides what mods will be used. The host can pick speed-altering mods regardless of whether or not Free Mods is turned on.\n8. The team mode and win conditions.\n9. The ready button.\n10. The [chat console](/wiki/Chat_Console).\n11. The leave button.\n12. Where your activated mods appear.\n\n## Song Selection Screen\n\n![](img/song-selection.jpg \"Song Selection\")\n\nYou can identify the current mode selected by either looking at the icon in the bottom left, above Mode, or by looking at the transparent icon in the center of the screen. These are the four you will see:\n\n- ![](/wiki/shared/mode/osu.png) is [osu!](/wiki/Game_mode/osu!)\n- ![](/wiki/shared/mode/taiko.png) is [osu!taiko](/wiki/Game_mode/osu!taiko)\n- ![](/wiki/shared/mode/catch.png) is [osu!catch](/wiki/Game_mode/osu!catch)\n- ![](/wiki/shared/mode/mania.png) is [osu!mania](/wiki/Game_mode/osu!mania)\n\nBefore continuing on, this screen has too many elements to note with easily, noticeable numbers. The subsections below will focus on one part of the screen at a time, starting from the top down and left to right.\n\n### Beatmap Information\n\n![](img/metadata-comparison.jpg)\n\n![](img/beatmap-metadata.jpg)\n\nThis area displays **information on the beatmap difficulty currently selected.** By default, the beatmap whose song is heard in the osu! jukebox is selected when entering the selection screen. In the top left is the ranked status of the beatmap. The title is next. Normally, the romanised title is shown, but if you select `Prefer metadata in original language` in the [Options](/wiki/Options), it will show the Unicode title; this is shown in the upper picture. The beatmapper is also shown, and beatmap information is shown below. From left to right, the values are as follows:\n\n- **Length**: The total length of the beatmap, from start to finish and including breaks. Not to be confused with [drain time](/wiki/Glossary#drain-time).\n- **BPM**: The BPM of the beatmap. If (like in the lower picture) there are two BPMS and one in parentheses, this means that the BPM changes throughout the song. It shows the slowest and fastest BPMs, and the value in parentheses is the BPM at the start of the beatmap.\n- **Objects**: The total amount of [hit objects](/wiki/Hit_Objects) in the beatmap.\n- **Circles**: The total amount of hit circles in the beatmap.\n- **Sliders**: The total amount of sliders in the beatmap.\n- **Spinners**: The total amount of spinners in the beatmap.\n- **OD**: The Overall Difficulty of the beatmap.\n- **HP**: The drain rate of your HP. In osu!, this is how much of an HP loss you receive upon missing a note, how fast the life bar idly drains, and how much HP is received for hitting a note. In osu!mania, this is the same except there is no idle HP drain. In osu!taiko, this determines how slowly the HP bar fills and how much HP is lost when a note is missed. osu!catch is the same as osu!.\n- **Stars**: The star difficulty of the beatmap. This is graphically visible in the beatmap rectangle itself.\n\n### Group and Sort\n\n![](img/beatmap-filters.jpg)\n\nClick on one of the tabs to **sort your song list according to the selected criterion**.\n\n**Group** - Most options organize beatmaps into various expandable groups:\n\n- `No grouping` - Beatmaps will not be grouped but will still be sorted in the order specified by Sort.\n- `By Difficulty` - Beatmaps will be grouped by their star difficulty, rounded to the nearest whole number.\n- `By Artist` - Beatmaps will be grouped by the artist's first character of their name.\n- `Recently Played` - Beatmaps will be grouped by when you last played them.\n- `Collections` - This will show the collections you have created. *Note that this will hide beatmaps not listed in a collection!*\n- `By BPM` - Beatmaps will be grouped according to BPM in multiples of 60, starting at 120.\n- `By Creator` - Beatmaps will be grouped by the beatmap creator's name's first character.\n- `By Date Added` - Beatmaps will be grouped according to when they were added, from today to 4+ months ago.\n- `By Length` - Beatmaps will be grouped according to their length: 1 minute or less, 2 minutes or less, 3, 4, 5, and 10.\n- `By Mode` - Beatmaps will be grouped according to their game mode.\n- `By Rank Achieved` - Beatmaps will be sorted by the highest rank achieved on them.\n- `By Title` - Beatmaps will be grouped by the first letter of their title.\n- `Favourites` - Only beatmaps you have favorited online will be shown.\n- `My Maps` - Only beatmaps you have mapped (that is, whose creator matches your profile name) will be shown.\n- `Ranked Status` - Beatmaps will be grouped by their ranked status: ranked, pending, not submitted, unknown, or loved.\n\nThe first five groupings are available in tabs below Group and Sort.\n\n**Sort** - Sorts beatmaps in a certain order\n\n- `By Artist` - Beatmaps will be sorted alphabetically by the artist's name's first character.\n- `By BPM` - Beatmaps will be sorted lowest to highest by their BPM. For maps with multiple BPMs, the highest will be used.\n- `By Creator` - Beatmaps will be sorted alphabetically by the creator's name's first character.\n- `By Date Added` - Beatmaps will be sorted from oldest to newest by when they were added.\n- `By Difficulty` - Beatmaps will be sorted from easiest to hardest by star difficulty. *Note that this will split apart mapsets!*\n- `By Length` - Beatmaps will be sorted from shortest to longest by length.\n- `By Rank Achieved` - Beatmaps will be sorted from poorest to best by the highest rank achieved on them.\n- `By Title` - Beatmaps will be sorted alphabetically by the first character of their name.\n\n### Search\n\n![](img/search-bar.jpg)\n\n*Note: You cannot have the chat console or the options sidebar open if you want to search; otherwise, anything you type will be perceived as chat text or as an options search query.*\n\nOnly beatmaps that match the criteria of your search will be shown. By default, any search will be matched against the beatmaps' artists, titles, creators, and tags.\n\nIn addition to searching these fields, you can use filters to search through other metadata by combining one of the supported filters with a comparison to a value (for example, `ar=9`).\n\nSupported filters:\n\n- `artist`: Name of the artist\n- `creator`: Name of the beatmap creator\n- `ar`: Approach Rate\n- `cs`: Circle Size\n- `od`: Overall Difficulty\n- `hp`: HP Drain Rate\n- `keys`: Number of keys (osu!mania and converted beatmaps only)\n- `stars`: Star Difficulty\n- `bpm`: Beats per minute\n- `length`: Length in seconds\n- `drain`: Drain Time in seconds\n- `mode`: Mode. Value can be `osu`, `taiko`, `catchthebeat`, or `mania`, or `o`/`t`/`c`/`m` for short.\n- `status`: Ranked status. Value can be `ranked`, `approved`, `pending`, `notsubmitted`, `unknown`, or `loved`, or `r`/`a`/`p`/`n`/`u`/`l` for short.\n- `played`: Time since last played in days\n- `unplayed`: Shows only unplayed maps. A comparison with no set value must be used. The comparison itself is ignored.\n- `speed`: Saved osu!mania scroll speed. Always 0 for unplayed maps or if the [Remember osu!mania scroll speed per beatmap](/wiki/Options#gameplay) option is off\n\nSupported comparisons:\n\n- `=` or `==`: Equal to\n- `!=`: Not equal to\n- `<`: Less than\n- `>`: Greater than\n- `<=`: Less than or equal to\n- `>=`: Greater than or equal to\n\nYou may also enter a beatmap or beatmapset ID in your search to get a single result.\n\n### Rankings\n\n![](img/leaderboards.jpg)\n\n A variety of things can appear in this space:\n\n- A \"Not Submitted\" box denotes a beatmap that has not been uploaded to the osu! site using the Beatmap Submission System or was deleted by the mapper.\n- An \"Update to latest version\" box appears if there is a new version of the beatmap available for download. Click on the button to update.\n - **Note:** Once you update the beatmap, it cannot be reversed. If you want to preserve the older version for some reason (say, to keep scores), then do not update.\n- A \"Latest pending version\" box appears means that the beatmap has been uploaded to the osu!website but is not ranked yet.\n- If replays matching the view setting of the beatmap exist, they will be displayed instead of a box denoting the ranked/played status of the beatmap. This is shown in the above picture.\n - Under public rankings (e.g. Global, Friends, etc.), your high score will be shown at the bottom, as well as your rank on the leaderboard.\n- A \"No records set!\" box means that there are no replays for the current view setting (this is typically seen in the Local view setting if you just downloaded or edited the beatmap).\n - Note: Scores for Multi are not counted as records.\n\nThese are the view settings:\n\n- Local Ranking\n- Country Ranking\\*\n- Global Ranking\n- Global Ranking (Selected Mods)\\*\n- Friend Ranking\\*\n\n\\*Requires you to be an [osu!supporter](/wiki/osu!supporter) to access them.\n\nClick the word bubble icon to call up the **Quick Web Access** screen for the selected beatmap:\n\n- Press `1` or click the `Beatmap Listing/Scores` button and your default internet browser will pull up the Beatmap Listing and score page of the beatmap set the selected beatmap belongs to.\n- Press `2` or click `Beatmap Modding` and your default internet browser will pull up the modding page of the beatmap set the selected beatmap belongs to.\n- Press `3` or `Esc` or click `Cancel` to return to the Song Selection Screen.\n\nWhile you are on the Quick Web Access Screen, you cannot access the Chat and Extended Chat Consoles.\n\n### Song\n\n![](img/beatmap-cards.jpg)\n\nThe song list displays all available beatmaps. Different beatmaps may have different coloured boxes:\n\n- **Pink**: This beatmap has not been played yet.\n- **Orange**: At least one beatmap from the beatmapset has been completed.\n- **Light Blue**: Other beatmaps in the same set, shown when a mapset is expanded.\n- **White**: Currently selected beatmap.\n\nYou can navigate the beatmap list by using the mouse wheel, using the up and down arrow keys, dragging it while holding the left mouse button or clicking the right mouse button (previously known as Absolute Scrolling), which will move the scroll bar to your mouse's Y position. Click on a box to select that beatmap and display its information on the upper left, high scores (if any) on the left and, if you've cleared it, the letter grade of the highest score you've achieved. Click the box again, press `Enter` or click the osu!cookie at the lower right to begin playing the beatmap.\n\n### Gameplay toolbox\n\n![](img/game-mode-selector.jpg \"List of available game modes\")\n\n![](img/gameplay-toolbox.jpg)\n\nThis section can be called the gameplay toolbox. We will cover each button's use from left to right.\n\nPress `Esc` or click the `Back` button to return to main menu.\n\nClick on the `Mode` button to open up a list of gameplay modes available on osu!. Click on your desired gameplay mode and osu! will switch to that gameplay mode style - the scoreboard will change accordingly. Alternatively, you can press `Ctrl` and `1` (osu!), `2` (osu!taiko), `3` (osu!catch), or `4` (osu!mania) to change the gamemode.\n\nThe background transparent icon and the \"Mode\" box will change to depict what mode is currently selected.\n\n![](img/game-modifiers.jpg \"Mod Selection Screen\")\n\nClick the `Mods` button or press `F1` to open the **[Mod Selection Screen](/wiki/Game_modifier)**.\n\nIn this screen, you can apply modifications (\"mods\" for short) to gameplay. Some mods lower difficulty and apply a multiplier that lowers the score you achieve. Conversely, some mods increase the difficulty, but apply a multiplier that increases the score you achieve. Finally, some mods modify gameplay in a different way. [Relax](/wiki/Game_modifier/Relax) and [Auto Pilot](/wiki/Game_modifier/Autopilot) fall in that category.\n\nPlace your mouse on a mod's icon to see a short description of its effect. Click on an icon to select or deselect that mod. Some mods, like Double Time, have multiple variations; click on the mod again to cycle through. The score multiplier value displays the combined effect the multipliers of the mod(s) of you have selected will have on your score. Click `Reset all mods` or press `1` to deselect all currently selected mods. Click `Close` or press `2` or `Esc` to return to the Song Selection Screen.\n\nWhile you are on the Mod Selection Screen, you cannot access the Chat and Extended Chat Consoles. In addition, skins can alter the text and/or icon of the mods, but the effects will still be the same.\n\nClick the `Random` button or press `F2` to have the game **randomly scroll through all of your beatmaps and pick one.** You cannot select a beatmap yourself until it has finished scrolling.\n\n*Note: You can press `Shift` + the `Random` button or `F2` to go back to the beatmap you had selected before you randomized your selection.*\n\n![](img/beatmap-options.jpg \"Possible commands for a beatmap\")\n\nClick the `Beatmap Options` button, press `F3` or right-click your mouse while hovering over the beatmap to call up the **Beatmap Options Menu for options on the currently selected beatmap**.\n\n- Press `1` or click the `Manage Collections` button to bring up the Collections screen - here, you can manage pre-existing collections, as well as add or remove the currently selected beatmap or mapset to or from a collection.\n- Press `2` or click `Delete...` to delete the \\[1\\] currently selected beatmapset, \\[2\\] delete the currently selected beatmap, or \\[3\\] delete **all VISIBLE beatmaps**.\n - Note that deleted beatmaps are moved to the Recycle Bin.\n- Press `3` or click `Remove from Unplayed` to mark an unplayed beatmap as played (that is, change its box colour from pink to orange).\n- Press `4` or click `Clear local scores` to delete all records of the scores you have achieved in this beatmap.\n- Press `5` or click `Edit` to open the selected beatmap in osu!'s Editor.\n- Press `6` or `Esc` or click `Close` to return to the Song Selection Screen.\n\nClick on **your user panel** to access the **User Options Menu**.\n\nClick the **[osu!cookie](/wiki/Glossary#cookie)** to **start playing the selected beatmap**.\n\n## Results screen\n\n![](img/results-osu.jpg \"Accuracy in osu!\")\n\nThis is the results screen shown after you have successfully passed the beatmap. You can access your online results by scrolling down or pressing the obvious button.\n\n**Note:** The results screen may change depending on the used skin.\n\nBelow are the results screens of the other game modes.\n\n![](img/results-taiko.jpg \"Accuracy in osu!taiko\")\n\n![](img/results-mania.jpg \"Accuracy in osu!mania\")\n\n![](img/results-catch.jpg \"Accuracy in osu!catch\")\n\n### Online Leaderboard\n\n![](img/extended-results-screen.jpg \"An example of an osu!online score\")\n\nThis is your online leaderboard. You can go here by scrolling down from the results screen. Your Local Scoreboard will show your name and the score as usual.\n\n1. Your player bar. It shows your [PP](/wiki/Performance_Points), Global Rank, Total Score, Overall [Accuracy](/wiki/Accuracy), and level bar.\n2. `Save replay to Replays folder`: You can watch the replay later either by opening it from a local leaderboard, or by going to `Replays` directory and double clicking it.\n3. `Add as online favourite`: Include the beatmap into your list of favourites, which is located on your osu! profile page under the \"Beatmaps\" section.\n4. Local Leaderboard: All your results are stored on your computer. To see them, navigate to the [song selection screen](#song-selection-screen), then select `Local Rankings` from the drop-down menu on the left.\n5. `Beatmap Ranking` section. Available only for maps with online leaderboards ([qualified](/wiki/Beatmap/Category#qualified), [ranked](/wiki/Beatmap/Category#ranked), or [loved](/wiki/Beatmap/Category#loved)). You also need to be online to see this section.\n 1. `Overall`: Your position on the map's leaderboard, where you compete against players that used [mods](/wiki/Game_modifier), even if you didn't use any yourself.\n 2. `Accuracy`: How [precisely](/wiki/Accuracy) did you play the beatmap. Will only be counted when your old score is surpassed.\n 3. `Max Combo`: Your longest combo on the map you played.\n 4. `Ranked Score`: Your [best result](/wiki/Score#ranked-score) on the beatmap.\n 5. `Total Score`: Not taken into account, since it does not affect your position in online rankings.\n 6. `Performance`: The amount of [unweighted PP](/wiki/Performance_points#why-didnt-i-gain-the-full-amount-of-pp-from-a-map-i-played) you would receive for the play.\n6. `Overall Ranking` section. It's available only for beatmaps with online leaderboards. You also need to be online to see this section.\n 1. `Overall`: Your global ranking in the world.\n 2. `Accuracy`: Your average [accuracy](/wiki/Accuracy#accuracy) over all beatmaps you have played.\n 3. `Max Combo`: The longest combo over all beatmaps you have played.\n 4. [`Ranked Score`](/wiki/Score#ranked-score): The number of points earned from all ranked beatmaps that you have ever played, with every map being counted exactly once.\n 5. [`Total Score`](/wiki/Score#total-score): Same as ranked score, but it takes into account all beatmaps available on the osu! website, and also underplayed or failed beatmaps. This counts towards your level.\n 6. `Perfomance`: Displays your total amount of Performance Points, and also how many PP the submitted play was worth.\n7. Information about the beatmap with its playcount and pass rate.\n8. Beatmap rating. Use your personal discretion based on whether you enjoy the beatmap or not. Best left alone if you can't decide.\n9. Click here to return to the song selection screen.\n\n![](img/medal-unlock.jpg \"Unlocking a medal\")\n\nAbove is what it looks like to receive a medal.\n", + "# Formatting\n\n*For the writing standards, see: [Article style criteria/Writing](../Writing)*\n\n*Notice: This article uses [RFC 2119](https://tools.ietf.org/html/rfc2119 \"IETF Tools\") to describe requirement levels.*\n\n## Locales\n\nListed below are the properly-supported locales for the wiki:\n\n| File Name | Locale Name | Native Script |\n| :-- | :-- | :-- |\n| `en.md` | English | English |\n| `ar.md` | Arabic | اَلْعَرَبِيَّةُ |\n| `be.md` | Belarusian | Беларуская мова |\n| `bg.md` | Bulgarian | Български |\n| `cs.md` | Czech | Česky |\n| `da.md` | Danish | Dansk |\n| `de.md` | German | Deutsch |\n| `gr.md` | Greek | Ελληνικά |\n| `es.md` | Spanish | Español |\n| `fi.md` | Finnish | Suomi |\n| `fr.md` | French | Français |\n| `hu.md` | Hungarian | Magyar |\n| `id.md` | Indonesian | Bahasa Indonesia |\n| `it.md` | Italian | Italiano |\n| `ja.md` | Japanese | 日本語 |\n| `ko.md` | Korean | 한국어 |\n| `nl.md` | Dutch | Nederlands |\n| `no.md` | Norwegian | Norsk |\n| `pl.md` | Polish | Polski |\n| `pt.md` | Portuguese | Português |\n| `pt-br.md` | Brazilian Portuguese | Português (Brasil) |\n| `ro.md` | Romanian | Română |\n| `ru.md` | Russian | Русский |\n| `sk.md` | Slovak | Slovenčina |\n| `sv.md` | Swedish | Svenska |\n| `th.md` | Thai | ไทย |\n| `tr.md` | Turkish | Türkçe |\n| `uk.md` | Ukrainian | Українська мова |\n| `vi.md` | Vietnamese | Tiếng Việt |\n| `zh.md` | Chinese (Simplified) | 简体中文 |\n| `zh-tw.md` | Traditional Chinese (Taiwan) | 繁體中文(台灣) |\n\n*Note: The website will give readers their selected language's version of an article. If it is not available, the English version will be given.*\n\n### Content parity\n\nTranslations are subject to strict content parity with their English article, in the sense that they must have the same message, regardless of grammar and syntax. Any changes to the translations' meanings must be accompanied by equivalent changes to the English article.\n\nThere are some cases where the content is allowed to differ:\n\n- Articles originally written in a language other than English (in this case, English should act as the translation)\n- Explanations of English words that are common terms in the osu! community\n- External links\n- Tags\n- Subcommunity-specific explanations\n\n## Front matter\n\nFront matter must be placed at the very top of the file. It is written in [YAML](https://en.wikipedia.org/wiki/YAML#Example \"YAML Wikipedia article\") and describes additional information about the article. This must be surrounded by three hyphens (`---`) on the lines above and below it, and an empty line must follow it before the title heading.\n\n### Articles that need help\n\n*Note: Avoid translating English articles with this tag. In addition to this, this tag should be added when the translation needs its own clean up.*\n\nThe `needs_cleanup` tag may be added to articles that need rewriting or formatting help. It is also acceptable to open an issue on GitHub for this purpose. This tag must be written as shown below:\n\n```yaml\nneeds_cleanup: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be done to remove the tag.\n\n### Outdated articles\n\n*Note: Avoid translating English articles with this tag. If the English article has this tag, the translation must also have this tag.*\n\nTranslated articles that are outdated must use the `outdated` tag when the English variant is updated. English articles may also become outdated when the content they contain is misleading or no longer relevant. This tag must be written as shown below:\n\n```yaml\noutdated: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be updated to remove the tag.\n\n### Tagging articles\n\nTags help the website's search engine query articles better. Tags should be written in the same language as the article and include the original list of tags. Tags should use lowercase letters where applicable.\n\nFor example, an article called \"Beatmap discussion\" may include the following tags:\n\n```yaml\ntags:\n - beatmap discussions\n - modding V2\n - MV2\n```\n\n### Translations without reviews\n\n*Note: Wiki maintainers will determine and apply this mark prior to merging.*\n\nSometimes, translations are added to the wiki without review from other native speakers of the language. In this case, the `no_native_review` mark is added to let future translators know that it may need to be checked again. This tag must be written as shown below:\n\n```yaml\nno_native_review: true\n```\n\n## Article naming\n\n*See also: [Folder names](#folder-names) and [Titles](#titles)*\n\nArticle titles should be singular and use sentence case. See [Wikipedia's naming conventions article](https://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(plurals) \"Wikipedia\") for more details.\n\nArticle titles should match the folder name it is in (spaces may replace underscores (`_`) where appropriate). If the folder name changes, the article title should be changed to match it and vice versa.\n\n---\n\nContest and tournament articles are an exception. The folder name must use abbreviations, acronyms, or initialisms. The article's title must be the full name of the contest or tournament.\n\n## Folder and file structure\n\n### Folder names\n\n*See also: [Article naming](#article-naming)*\n\nFolder names must be in English and use sentence case.\n\nFolder names must only use these characters:\n\n- uppercase and lowercase letters\n- numbers\n- underscores (`_`)\n- hyphens (`-`)\n- exclamation marks (`!`)\n\n### Article file names\n\nThe file name of an article can be found in the `File Name` column of the [locales section](#locales). The location of a translated article must be placed in the same folder as the English article.\n\n### Index articles\n\nAn index article must be created if the folder is intended to only hold other articles. Index articles must contain a list of articles that are inside its own folder. They may also contain other information, such as a lead paragraph or descriptions of the linked articles.\n\n### Disambiguation articles\n\n[Disambiguation](/wiki/Disambiguation) articles must be placed in the `/wiki/Disambiguation` folder. The main page must be updated to include the disambiguation article. Refer to [Disambiguation/Mod](/wiki/Disambiguation/Mod) as an example.\n\nRedirects must be updated to have the ambiguous keyword(s) redirect to the disambiguation article.\n\nArticles linked from a disambiguation article must have a [For other uses](#for-other-uses) hatnote.\n\n## HTML\n\nHTML must not be used, with exception for [comments](#comments). The structure of the article must be redone if HTML is used.\n\n### Comments\n\nHTML comments should be used for marking to-dos, but may also be used to annotate text. They should be on their own line, but can be placed inline in a paragraph. If placed inline, the start of the comment must not have a space.\n\nBad example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\nGood example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\n## Editing\n\n### End of line sequence\n\n*Caution: Uploading Markdown files using `CRLF` (carriage return and line feed) via GitHub will result in those files using `CRLF`. To prevent this, set the line ending to `LF` (line feed) before uploading.*\n\nMarkdown files must be checked in using the `LF` end of line sequence.\n\n### Escaping\n\nMarkdown syntax should be escaped as needed. However, article titles are parsed as plain text and so must not be escaped.\n\n### Paragraphs\n\nEach paragraph must be followed by one empty line.\n\n### Line breaks\n\nLine breaks must use a backslash (`\\`).\n\nLine breaks must be used sparingly.\n\n## Hatnote\n\n*Not to be confused with [Notice](#notice).*\n\nHatnotes are short notes placed at the top of an article or section to help readers navigate to related articles or inform them about related topics.\n\nHatnotes must be italicised and be placed immediately after the heading. If multiple hatnotes are used, they must be on the same paragraph separated with a line break.\n\n### Main page\n\n*Main page* hatnotes direct the reader to the main article of a topic. When this hatnote is used, it implies that the section it is on is a summary of what the linked page is about. This hatnote should have only one link. These must be formatted as follows:\n\n```markdown\n*Main page: {article}*\n\n*Main pages: {article} and {article}*\n```\n\n### See also\n\n*See also* hatnotes suggest to readers other points of interest from a given article or section. These must be formatted as follows:\n\n```markdown\n*See also: {article}*\n\n*See also: {article} and {article}*\n```\n\n### For see\n\n*For see* hatnotes are similar to *see also* hatnotes, but are generally more descriptive and direct. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*For {description}, see: {article}`*\n\n*For {description}, see: {article} and {article}`*\n```\n\n### Not to be confused with\n\n*Not to be confused with* hatnotes help distinguish ambiguous or misunderstood article titles or sections. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*Not to be confused with {article}.*\n\n*Not to be confused with {article} or {article}.*\n```\n\n### For other uses\n\n*For other uses* hatnotes are similar to *not to be confused with* hatnotes, but links directly to the [disambiguation article](#disambiguation-articles). This hatnote must only link to the disambiguation article. These must be formatted as follows:\n\n```markdown\n*For other uses, see {disambiguation article}.*\n```\n\n## Notice\n\n*Not to be confused with [Hatnote](#hatnote).*\n\nA notice should be placed where appropriate in a section, but must start off the paragraph and use italics. Notices may contain bolding where appropriate, but should be kept to a minimum. Notices must be written as complete sentences. Thus, unlike most [hatnotes](#hatnotes), must use a full stop (`.`) or an exclamation mark (`!`) if appropriate. Anything within the same paragraph of a notice must also be italicised. These must be formatted as follows:\n\n```markdown\n*Note: {note}.*\n\n*Notice: {notice}.*\n\n*Caution: {caution}.*\n\n*Warning: {warning}.*\n```\n\n- `Note` should be used for factual or trivial details.\n- `Notice` should be used for reminders or to draw attention to something that the reader should be made aware of.\n- `Caution` should be used to warn the reader to avoid unintended consequences.\n- `Warning` should be used to warn the reader that action may be taken against them.\n\n## Emphasising\n\n### Bold\n\nBold must use double asterisks (`**`).\n\nLead paragraphs may bold the first occurrence of the article's title.\n\n### Italics\n\nItalics must use single asterisks (`*`).\n\nNames of work or video games should be italicised. osu!—the game—is exempt from this.\n\nThe first occurrence of an abbreviation, acronym, or initialism may be italicised.\n\nItalics may also be used to provide emphasis or help with readability.\n\n## Headings\n\nAll headings must use sentence case.\n\nHeadings must use the [ATX (hash) style](https://github.github.com/gfm/#atx-headings \"GitHub\") and must have an empty line before and after the heading. The title heading is an exception when it is on the first line. If this is the case, there only needs to be an empty line after the title heading.\n\nHeadings must not exceed a heading level of 5 and must not be used to style or format text.\n\n### Titles\n\n*See also: [Article naming](#article-naming)*\n\n*Caution: Titles are parsed as plain text; they must not be escaped.*\n\nThe first heading in all articles must be a level 1 heading, being the article's title. All headings afterwards must be [section headings](#sections). Titles must not contain formatting, links, or images.\n\nThe title heading must be on the first line, unless [front matter](#front-matter) is being used. If that is the case, the title heading must go after it and have an empty line before the title heading.\n\n### Sections\n\nSection headings must use levels 2 to 5. The section heading proceeding the [title heading](#titles) must be a level 2 heading. Unlike titles, section headings may have small image icons.\n\nSection headings must not skip a heading level (i.e. do not go from a level 2 heading to a level 4 heading) and must not contain formatting or links.\n\n*Notice: On the website, heading levels 4 and 5 will not appear in the table of contents. They cannot be linked to directly either.*\n\n## Lists\n\nLists should not go over 4 levels of indentation and should not have an empty line in between each item.\n\nFor nested lists, bullets or numbers must align with the item content of their parent lists.\n\nThe following example was done incorrectly (take note of the spacing before the bullet):\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\nThe following example was done correctly:\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\n### Bulleted\n\nBulleted lists must use a hyphen (`-`). These must then be followed by one space. (Example shown below.)\n\n```markdown\n- osu!\n - Hit circle\n - Combo number\n - Approach circle\n - Slider\n - Hit circles\n - Slider body\n - Slider ticks\n - Spinner\n- osu!taiko\n```\n\n### Numbered\n\nThe numbers in a numbered list must be incremented to represent their step.\n\n```markdown\n1. Download the osu! installer.\n2. Run the installer.\n 1. To change the installation location, click the text underneath the progression bar.\n 2. The installer will prompt for a new location, choose the installation folder.\n3. osu! will start up once installation is complete.\n4. Sign in.\n```\n\n### Mixed\n\nCombining both bulleted and numbered lists should be done sparingly.\n\n```markdown\n1. Download a skin from the forums.\n2. Load the skin file into osu!.\n - If the file is a `.zip`, unzip it and move the contents into the `Skins/` folder (found in your osu! installation folder).\n - If the file is a `.osk`, open it on your desktop or drag-and-drop it into the game client.\n3. Open osu!, if it is not opened, and select the skin in the options.\n - This may have been completed if you opened the `.osk` file or drag-and-dropped it into the game client.\n```\n\n## Code\n\nThe markup for code is a grave mark (`` ` ``). To put grave marks in code, use double grave marks instead. If the grave mark is at the start or end, pad it with one space. (Example shown below.)\n\n```markdown\n`` ` ``\n`` `Space` ``\n```\n\n### Keyboard keys\n\n*Notice: When denoting the letter itself, and not the keyboard key, use quotation marks instead.*\n\nWhen representing keyboard keys, use capital letters for single characters and title case for modifiers. Use the plus symbol (`+`) (without code) to represent key combinations. (Example shown below.)\n\n```markdown\npippi is spelt with a lowercase \"p\" like peppy.\n\nPress `Ctrl` + `O` to open the open dialog.\n```\n\nWhen representing a space or the spacebar, use `` `Space` ``.\n\n### Button and menu text\n\nWhen copying the text from a menu or button, the letter casing should be copied as it appears. (Example shown below.)\n\n```markdown\nThe `osu!direct` button is visible in the main menu on the right side, if you have an active osu!supporter tag.\n```\n\n### Folder and directory names\n\nWhen copying the name of a folder or directory, the letter casing should be copied as it appears, but prefer lowercased paths when possible. Directory paths must not be absolute (i.e. do not start the directory name from the drive letter or from the root folder). (Example shown below.)\n\n```markdown\nosu! is installed in the `AppData/Local` folder by default, unless specified otherwise during installation.\n```\n\n### Keywords and commands\n\nWhen copying a keyword or command, the letter casing should be copied as it appears or how someone normally would type it. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nAs of now, the `Name` and `Author` commands in the skin configuration file (`skin.ini`) do nothing.\n```\n\n### File names\n\nWhen copying the name of a file, the letter casing should be copied as it appears. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nTo play osu!, double click the `osu!.exe` icon.\n```\n\n### File extensions\n\n*Notice: File formats (not to be confused with file extensions) must be written in capital letters without the prefixed fullstop (`.`).*\n\nFile extensions must be prefixed with a fullstop (`.`) and be followed by the file extension in lowercase letters. (Example shown below.)\n\n```markdown\nThe JPG (or JPEG) file format has the `.jpg` (or `.jpeg`) extension.\n```\n\n### Chat channels\n\nWhen copying the name of a chat channel, start it with a hash (`#`), followed by the channel name in lowercase letters. (Example shown below.)\n\n```markdown\n`#lobby` is where you can advertise your multi room.\n```\n\n## Preformatted text (code blocks)\n\n*Notice: Syntax highlighting for preformatted text is not implemented on the website yet.*\n\nPreformatted text (also known as code blocks) must be fenced using three grave marks. They should set the language identifier for syntax highlighting.\n\n## Links\n\nThere are two types of links: inline and reference. Inline has two styles.\n\nThe following is an example of both inline styles:\n\n```markdown\n[Game Modifiers](/wiki/Game_Modifiers)\n\n\n```\n\nThe following is an example of the reference style:\n\n```markdown\n[Game Modifiers][game mods link]\n\n[game mods link]: /wiki/Game_Modifiers\n```\n\n---\n\nLinks must use the inline style if they are only referenced once. The inline angle brackets style should be avoided. References to reference links must be placed at the bottom of the article.\n\n### Internal links\n\n*Note: Internal links refer to links that stay inside the `https://osu.ppy.sh/` domain.*\n\n#### Wiki links\n\nAll links that point to an wiki article should start with `/wiki/` followed by the path to get to the article you are targeting. Relative links may also be used. Some examples include the following:\n\n```markdown\n[FAQ](/wiki/FAQ)\n[pippi](/wiki/Mascots#-pippi)\n[Beatmaps](../)\n[Pattern](./Pattern)\n```\n\nWiki links must not use redirects and must not have a trailing forward slash (`/`).\n\nBad examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/ASC)\n[Developers](/wiki/Developers/)\n[Developers](/wiki/Developers/#game-client-developers)\n```\n\nGood examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/Article_styling_criteria)\n[Developers](/wiki/Developers)\n[Developers](/wiki/Developers#game-client-developers)\n```\n\n##### Sub-article links\n\nWiki links that point to a sub-article should include the parent article's folder name in its link text. See the following example:\n\n```markdown\n*See also: [Beatmap Editor/Design](/wiki/Beatmap_Editor/Design)*\n```\n\n##### Section links\n\n*Notice: On the website, heading levels 4 and 5 are not given the id attribute. This means that they can not be linked to directly.*\n\nWiki links that point to a section of an article may use the section sign symbol (`§`). See the following example:\n\n```markdown\n*For timing rules, see: [Ranking Criteria § Timing](/wiki/Ranking_Criteria#timing)*\n```\n\n#### Other osu! links\n\nThe URL from the address bar of your web browser should be copied as it is when linking to other osu! web pages. The `https://osu.ppy.sh` part of the URL must be kept.\n\n##### User profiles\n\nAll usernames must be linked on first occurrence. Other occurrences are optional, but must be consistent throughout the entire article for all usernames. If it is difficult to determine the user's id, it may be skipped over.\n\nWhen linking to a user profile, the user's id number must be used. Use the new website (`https://osu.ppy.sh/users/{username})`) to get the user's id.\n\nThe link text of the user link should be the user's current name.\n\n##### Difficulties\n\nWhenever linking to a single difficulty, use this format as the link text:\n\n```\n{artist} - {title} ({creator}) [{difficuty_name}]\n```\n\nThe link must actually link to that difficulty. Beatmap difficulty URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}#{mode}/{BeatmapID}\n```\n\nThe difficulty name may be left outside of the link text, but doing so must be consistent throughout the entire article.\n\n##### Beatmaps\n\nWhenever linking to a beatmap, use this format as the link text:\n\n```\n{artist} - {title} ({creator})\n```\n\nAll beatmap URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}\n```\n\n### External links\n\n*Notice: External links refers to links that go outside the `https://osu.ppy.sh/` domain.*\n\nThe `https` protocol must be used, unless the site does not support it. External links must be a clean and direct link to a reputable source. The link text should be the title of the page it is linking to. The URL from the address bar of your web browser should be copied as it is when linking to other external pages.\n\nThere are no visual differences between external and osu! web links. Due to this, the website name should be included in the title text. See the following example:\n\n```markdown\n*For more information about music theory, see: [Music theory](https://en.wikipedia.org/wiki/Music_theory \"Wikipedia\")*\n```\n\n## Images\n\nThere are two types of image links: inline and reference. Examples:\n\n**Inline style:**\n\n```markdown\n![](/wiki/shared/flag/AU.gif)\n```\n\n**Reference style:**\n\n```markdown\n![][flag_AU]\n\n[flag_AU]: /wiki/shared/flag/AU.gif\n```\n\nImages should use the inline linking style. References to reference links must be placed at the bottom of the article.\n\nImages must be placed in a folder named `img`, located in the article's folder. Images that are used in multiple articles should be stored in the `/wiki/shared/` folder.\n\n### Image caching\n\nImages on the website are cached for up to 60 days. The cached image is matched with the image link's URL.\n\nWhen updating an image, either change the image's name or append a query string to the URL. In both cases, all translations linking to the updated image should also be updated.\n\n### Formats and quality\n\nImages should use the JPG format at quality 8 (80 or 80%, depending on the program). If the image contains transparency or has text that must be readable, use the PNG format instead. If the image contains an animation, the GIF format can be used; however, this should be used sparingly as these may take longer to load or can be bigger then the [max file size](#file-size).\n\n### File size\n\nImages must be under 1 megabyte, otherwise they will fail to load. Downscaling and using JPG at 80% is almost always under the size limit.\n\nAll images should be optimised as much as possible. Use [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive \"GitHub\") to compress JPEG images. For consistency, use the following command for jpeg-archive:\n\n```sh\njpeg-recompress -am smallfry \n```\n\nWhere `` is the file name to be compressed and `` is the compressed file name.\n\n### File names\n\n*Notice: File extensions must use lowercase letters, otherwise they will fail to load!*\n\nUse hyphens (`-`) when spacing words. When naming an image, the file name should be meaningful or descriptive but short.\n\n### Formatting and positioning\n\n*Note: It is currently not possible to float an image or have text wrap around it.*\n\nImages on the website will be centred when it is on a single line, by themself. Otherwise, they will be positioned inline with the paragraph. The following example will place the image in the center:\n\n```markdown\nInstalling osu! is easy. First, download the installer from the download page.\n\n![](img/download-page.jpg)\n\nThen locate the installer and run it.\n```\n\n### Alt text\n\nImages should have alt text unless it is for decorative purposes.\n\n### Captions\n\nImages are given captions on the website if they fulfill these conditions:\n\n1. The image is by itself.\n2. The image is not inside a heading.\n3. The image has title text.\n\nCaptions are assumed via the title text, which must be in plain text. Images with captions are also centred with the image on the website.\n\n### Max image width\n\nThe website's max image width is the width of the article body. Images should be no wider than 800 pixels.\n\n### Annotating images\n\nWhen annotating images, use *Torus Regular*. For Chinese, Korean, Japanese characters, use *Microsoft YaHei*.\n\nAnnotating images should be avoided, as it is difficult for translators (and other editors) to edit them.\n\n#### Translating annotated images\n\nWhen translating annotated images, the localised image version must be placed in the same directory as the original version (i.e. the English version). The filename of a localised image version must start with the original version's name, followed by a hyphen, followed by the locale name (in capital letters). See the following examples:\n\n- `hardrock-mod-vs-easy-mod.jpg` for English\n- `hardrock-mod-vs-easy-mod-DE.jpg` for German\n- `hardrock-mod-vs-easy-mod-ZH-TW.jpg` for Traditional Chinese\n\n### Screenshots of gameplay\n\nAll screenshots of gameplay must be done in the stable build, unless it is for a specific feature that is unavailable in the stable build. You should use the in-game screenshot feature (`F12`).\n\n#### Game client settings\n\n*Note: If you do not want to change your current settings for the wiki, you can move your `osu!..cfg` out of the osu! folder and move it back later.*\n\nYou must set these settings before taking a screenshot of the game client (settings not stated below are assumed to be at their defaults):\n\n- Select language: `English`\n- Prefer metadata in original language: `Enabled`\n- Resolution: `1280x720`\n- Fullscreen mode: `Disabled`\n- Parallax: `Disabled`\n- Menu tips: `Disabled`\n- Seasonal backgrounds: `Never`\n- Always show key overlay: `Enabled`\n- Current skin: `Default` (first option)\n\n*Notice to translators: If you are translating an article containing screenshots of the game, you may set the game client's language to the language you are translating in.*\n\n### Image links\n\nImages must not be part of a link text.\n\nFlag icons next to user links must be separate from the link text. See the following example:\n\n```markdown\n![][flag_AU] [peppy](https://osu.ppy.sh/users/2)\n```\n\n### Flag icons\n\n*For a list of flag icons, see: [issue \\#328](https://github.com/ppy/osu-wiki/issues/328 \"GitHub\")*\n\nThe flag icons use the two letter code (in all capital letters) and end with `.gif`. When adding a flag inline, use this format:\n\n```markdown\n![](/wiki/shared/flag/xx.gif)\n```\n\nWhere `xx` is the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 \"Wikipedia\") two-lettered country code for the flag.\n\nThe full country name should be added in the title text. The country code in the alternate text is optional, but must be applied to all flag icons in the article.\n\n## Tables\n\nTables on the website only support headings along the first row.\n\nTables must not be beautified (do not pad cells with extra spaces to make their widths uniform). They must have a vertical bar (`|`) on the left and right sides and the text of each cell must be padded with one space on both sides. Empty cells must use a vertical bar (`|`) followed by two spaces then another vertical bar (`|`).\n\nThe delimiter row (the next line after the table heading) must use only three characters per column (and be padded with a space on both sides), which must look like one of the following:\n\n- `:--` (for left align)\n- `:-:` (for centre align)\n- `--:` (for right align)\n\n---\n\nThe following is an example of what a table should look like:\n\n```markdown\n| Team \"Picturesque\" Red | Score | Team \"Statuesque\" Blue | Average Beatmap Stars |\n| :-- | :-: | --: | :-- |\n| **peppy** | 5 - 2 | pippi | 9.3 stars |\n| Aiko | 1 - 6 | **Alisa** | 4.2 stars |\n| Ryūta | 3 - 4 | **Yuzu** | 5.1 stars |\n| **Taikonator** | 7 - 0 | Tama | 13.37 stars |\n| Maria | No Contest | Mocha | |\n```\n\n## Blockquotes\n\nThe blockquote is limited to quoting text from someone. It must not be used to format text otherwise.\n\n## Thematic breaks\n\nThe thematic break (also known as the horizontal rule or line) should be used sparingly. A few uses of the thematic break may include (but is not limited to):\n\n- separating images from text\n- separating multiple images that follow one another\n- shifting the topic within a section\n\nThese must have an empty line before and after the markup. Thematic breaks must use only three hyphens, as depicted below:\n\n```markdown\n---\n```\n" }; } } From 7e781501443b62d2b3dc4102b2375c35252c7f42 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 10:16:49 +0700 Subject: [PATCH 05/44] add basic content wiki sidebar --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 6d1f520135..1f48d026ad 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -1,9 +1,36 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + namespace osu.Game.Overlays.Wiki { public class WikiSidebar : OverlaySidebar { + private FillFlowContainer tableOfContents; + + protected override Drawable CreateContent() => new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "CONTENTS", + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + }, + tableOfContents = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + } + }, + }; } } From b1b305c150aeb2bb5c6df0a7d62a9f72e5fcba3e Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 10:17:38 +0700 Subject: [PATCH 06/44] add method AddToc --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 1f48d026ad..0f4ae45650 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -3,6 +3,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; @@ -32,5 +33,19 @@ namespace osu.Game.Overlays.Wiki } }, }; + + public void AddToc(string title, MarkdownHeading heading, int level) + { + switch (level) + { + case 2: + tableOfContents.Add(new OsuSpriteText + { + Text = title, + Font = OsuFont.GetFont(size: 15), + }); + break; + } + } } } From abb522f084fa882fbf28dd858df0c1dcb0d8ecc6 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 10:53:48 +0700 Subject: [PATCH 07/44] add missing using --- osu.Game/Overlays/WikiOverlay.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 4cfbbbbfe4..812f26e77d 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -11,6 +11,7 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Wiki; +using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays { From 59dbed64180576aca1f8a7eaec39bfb550ebeb91 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:08:51 +0700 Subject: [PATCH 08/44] create ArticleMarkdownContainer in WikiArticlePage --- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 25 +++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index c41ab8b250..12a3ee386e 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -1,14 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays.Wiki { public class WikiArticlePage : GridContainer { + private readonly WikiSidebar sidebar; public Container SidebarContainer { get; } public WikiArticlePage(string currentPath, string markdown) @@ -31,9 +36,9 @@ namespace osu.Game.Overlays.Wiki SidebarContainer = new Container { AutoSizeAxes = Axes.X, - Child = new WikiSidebar(), + Child = sidebar = new WikiSidebar(), }, - new WikiMarkdownContainer + new ArticleMarkdownContainer { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, @@ -46,9 +51,25 @@ namespace osu.Game.Overlays.Wiki Left = 30, Right = 50, }, + OnAddHeading = sidebar.AddToc, } }, }; } + + private class ArticleMarkdownContainer : WikiMarkdownContainer + { + public Action OnAddHeading; + + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) + { + var heading = base.CreateHeading(headingBlock); + var title = ((LiteralInline)headingBlock.Inline.FirstChild).Content.ToString(); + + OnAddHeading(title, heading, headingBlock.Level); + + return heading; + } + } } } From d8d4bf66b3fdfd7367f347325d8a03f44b841fd7 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:09:20 +0700 Subject: [PATCH 09/44] create TocTitle in WikiSidebar --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 34 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 0f4ae45650..aa521d4ff5 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -1,10 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics; +using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Wiki @@ -39,13 +42,34 @@ namespace osu.Game.Overlays.Wiki switch (level) { case 2: - tableOfContents.Add(new OsuSpriteText - { - Text = title, - Font = OsuFont.GetFont(size: 15), - }); + tableOfContents.Add(new TocTitle(title)); break; } } + + private class TocTitle : OsuHoverContainer + { + private readonly OsuSpriteText spriteText; + + public TocTitle(string text) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Child = spriteText = new OsuSpriteText + { + Text = text, + Font = OsuFont.GetFont(size: 15), + }; + } + + protected override IEnumerable EffectTargets => new Drawable[] { spriteText }; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider) + { + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Light1; + } + } } } From 41ec531bab6c54a331ded55d8d86070f90e3ca35 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:12:42 +0700 Subject: [PATCH 10/44] add subtitle toc --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index aa521d4ff5..c2e28f4a81 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -44,6 +44,10 @@ namespace osu.Game.Overlays.Wiki case 2: tableOfContents.Add(new TocTitle(title)); break; + + case 3: + tableOfContents.Add(new TocTitle(title, true)); + break; } } @@ -51,14 +55,14 @@ namespace osu.Game.Overlays.Wiki { private readonly OsuSpriteText spriteText; - public TocTitle(string text) + public TocTitle(string text, bool subtitle = false) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Child = spriteText = new OsuSpriteText { Text = text, - Font = OsuFont.GetFont(size: 15), + Font = OsuFont.GetFont(size: subtitle ? 12 : 15), }; } From 424d1b402587256e5c872ac38ea91e20262eacbb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:18:08 +0700 Subject: [PATCH 11/44] add margin padding spacing in toc title --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index c2e28f4a81..e25e6189d7 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -64,6 +64,8 @@ namespace osu.Game.Overlays.Wiki Text = text, Font = OsuFont.GetFont(size: subtitle ? 12 : 15), }; + Margin = new MarginPadding { Top = subtitle ? 5 : 10 }; + Padding = new MarginPadding { Left = subtitle ? 10 : 0 }; } protected override IEnumerable EffectTargets => new Drawable[] { spriteText }; From 4e73d0254044741d8a34194dac3589566879c856 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:35:23 +0700 Subject: [PATCH 12/44] move sidebar into local variable --- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index 12a3ee386e..99068d6919 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -13,7 +13,6 @@ namespace osu.Game.Overlays.Wiki { public class WikiArticlePage : GridContainer { - private readonly WikiSidebar sidebar; public Container SidebarContainer { get; } public WikiArticlePage(string currentPath, string markdown) @@ -29,6 +28,9 @@ namespace osu.Game.Overlays.Wiki new Dimension(GridSizeMode.AutoSize), new Dimension(), }; + + WikiSidebar sidebar; + Content = new[] { new Drawable[] From e28b38653be073deae56b4cb2e44f31f0e101a6a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:43:00 +0700 Subject: [PATCH 13/44] cache scroll container --- osu.Game/Overlays/WikiOverlay.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 812f26e77d..5beb5d50e6 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -26,6 +26,9 @@ namespace osu.Game.Overlays [Resolved] private IAPIProvider api { get; set; } + [Cached] + private readonly OverlayScrollContainer scrollContainer; + private GetWikiRequest request; private CancellationTokenSource cancellationToken; @@ -37,6 +40,7 @@ namespace osu.Game.Overlays public WikiOverlay() : base(OverlayColourScheme.Orange, false) { + scrollContainer = ScrollFlow; } public void ShowPage(string pagePath = index_path) From 37ff6299c9c73df7c2eb374e3ab0acac57776e1d Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:43:32 +0700 Subject: [PATCH 14/44] add target in toc title --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index e25e6189d7..b3e315fefc 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -42,21 +42,25 @@ namespace osu.Game.Overlays.Wiki switch (level) { case 2: - tableOfContents.Add(new TocTitle(title)); - break; - case 3: - tableOfContents.Add(new TocTitle(title, true)); + tableOfContents.Add(new TocTitle(title, heading, level == 3)); break; } } private class TocTitle : OsuHoverContainer { + [Resolved] + private OverlayScrollContainer scrollContainer { get; set; } + private readonly OsuSpriteText spriteText; - public TocTitle(string text, bool subtitle = false) + private readonly MarkdownHeading target; + + public TocTitle(string text, MarkdownHeading target, bool subtitle = false) { + this.target = target; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; Child = spriteText = new OsuSpriteText From 91e77ee4dea2649d541ad9d305ba40b53aa6b922 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 11:43:49 +0700 Subject: [PATCH 15/44] add onclick in toc title --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index b3e315fefc..1c5e11a7ca 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; +using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -80,6 +81,12 @@ namespace osu.Game.Overlays.Wiki IdleColour = colourProvider.Light2; HoverColour = colourProvider.Light1; } + + protected override bool OnClick(ClickEvent e) + { + scrollContainer.ScrollTo(target); + return base.OnClick(e); + } } } } From a706ff63eddec695d2eaa039a1279fcdf086283a Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 12:50:03 +0700 Subject: [PATCH 16/44] change sprite text to text flow --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 1c5e11a7ca..d91076e40a 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -54,26 +54,30 @@ namespace osu.Game.Overlays.Wiki [Resolved] private OverlayScrollContainer scrollContainer { get; set; } - private readonly OsuSpriteText spriteText; - private readonly MarkdownHeading target; + private readonly OsuTextFlowContainer textFlow; + public TocTitle(string text, MarkdownHeading target, bool subtitle = false) { this.target = target; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - Child = spriteText = new OsuSpriteText + Child = textFlow = new OsuTextFlowContainer(t => { - Text = text, - Font = OsuFont.GetFont(size: subtitle ? 12 : 15), - }; + t.Font = OsuFont.GetFont(size: subtitle ? 12 : 15); + }).With(f => + { + f.AddText(text); + f.RelativeSizeAxes = Axes.X; + f.AutoSizeAxes = Axes.Y; + }); Margin = new MarginPadding { Top = subtitle ? 5 : 10 }; Padding = new MarginPadding { Left = subtitle ? 10 : 0 }; } - protected override IEnumerable EffectTargets => new Drawable[] { spriteText }; + protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) From 6c1fede18e0b0b133a89a7629f5aeb3db5439fe3 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 13:11:37 +0700 Subject: [PATCH 17/44] add wiki sidebar test scene --- .../Visual/Online/TestSceneWikiSidebar.cs | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs new file mode 100644 index 0000000000..fd7dbbe3ff --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Parsers; +using Markdig.Syntax; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Overlays; +using osu.Game.Overlays.Wiki; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiSidebar : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); + + [Cached] + private readonly OverlayScrollContainer scrollContainer = new OverlayScrollContainer(); + + private WikiSidebar sidebar; + + private readonly MarkdownHeading dummyHeading = new MarkdownHeading(new HeadingBlock(new HeadingBlockParser())); + + [SetUp] + public void SetUp() => Schedule(() => Child = sidebar = new WikiSidebar()); + + [Test] + public void TestNoContent() + { + AddStep("No Content", () => { }); + } + + [Test] + public void TestOnlyMainTitle() + { + AddStep("Add TOC", () => + { + for (var i = 0; i < 10; i++) + { + sidebar.AddToc($"This is a very long title {i + 1}", dummyHeading, 2); + } + }); + } + + [Test] + public void TestWithSubtitle() + { + AddStep("Add TOC", () => + { + for (var i = 0; i < 20; i++) + { + sidebar.AddToc($"This is a very long title {i + 1}", dummyHeading, i % 4 == 0 ? 2 : 3); + } + }); + } + } +} From 6d6c03eafe1980ee0c705ae4caf589bc4dc1c141 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 14:45:06 +0700 Subject: [PATCH 18/44] use linq to find first literal inline --- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index 99068d6919..a60bebdc4b 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using Markdig.Syntax; using Markdig.Syntax.Inlines; using osu.Framework.Graphics; @@ -66,7 +67,7 @@ namespace osu.Game.Overlays.Wiki protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) { var heading = base.CreateHeading(headingBlock); - var title = ((LiteralInline)headingBlock.Inline.FirstChild).Content.ToString(); + var title = ((LiteralInline)headingBlock.Inline.First(i => i is LiteralInline)).Content.ToString(); OnAddHeading(title, heading, headingBlock.Level); From 8883d5e2d1839056234d402bfb9188d7d64eeb93 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 15:21:44 +0700 Subject: [PATCH 19/44] use heading block to get title string --- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 7 ++---- osu.Game/Overlays/Wiki/WikiSidebar.cs | 26 ++++++++++++++++++++--- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index a60bebdc4b..83a61db88d 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -2,9 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Linq; using Markdig.Syntax; -using Markdig.Syntax.Inlines; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; @@ -62,14 +60,13 @@ namespace osu.Game.Overlays.Wiki private class ArticleMarkdownContainer : WikiMarkdownContainer { - public Action OnAddHeading; + public Action OnAddHeading; protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) { var heading = base.CreateHeading(headingBlock); - var title = ((LiteralInline)headingBlock.Inline.First(i => i is LiteralInline)).Content.ToString(); - OnAddHeading(title, heading, headingBlock.Level); + OnAddHeading(headingBlock, heading); return heading; } diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index d91076e40a..0db4d41b8b 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -2,6 +2,8 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -38,17 +40,35 @@ namespace osu.Game.Overlays.Wiki }, }; - public void AddToc(string title, MarkdownHeading heading, int level) + public void AddToc(HeadingBlock headingBlock, MarkdownHeading heading) { - switch (level) + switch (headingBlock.Level) { case 2: case 3: - tableOfContents.Add(new TocTitle(title, heading, level == 3)); + string title = getTitle(headingBlock.Inline); + tableOfContents.Add(new TocTitle(title, heading, headingBlock.Level == 3)); break; } } + private string getTitle(ContainerInline containerInline) + { + foreach (var inline in containerInline) + { + switch (inline) + { + case LiteralInline literalInline: + return literalInline.Content.ToString(); + + case LinkInline { IsImage: false } linkInline: + return getTitle(linkInline); + } + } + + return string.Empty; + } + private class TocTitle : OsuHoverContainer { [Resolved] From 3bf70dea60ed87d447cdbe64bc03cfc843bfc7b1 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 15:51:23 +0700 Subject: [PATCH 20/44] fix test to using heading block --- .../Visual/Online/TestSceneWikiSidebar.cs | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs index fd7dbbe3ff..a04a3eef6b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs @@ -3,9 +3,11 @@ using Markdig.Parsers; using Markdig.Syntax; +using Markdig.Syntax.Inlines; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays; using osu.Game.Overlays.Wiki; @@ -21,8 +23,6 @@ namespace osu.Game.Tests.Visual.Online private WikiSidebar sidebar; - private readonly MarkdownHeading dummyHeading = new MarkdownHeading(new HeadingBlock(new HeadingBlockParser())); - [SetUp] public void SetUp() => Schedule(() => Child = sidebar = new WikiSidebar()); @@ -38,9 +38,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Add TOC", () => { for (var i = 0; i < 10; i++) - { - sidebar.AddToc($"This is a very long title {i + 1}", dummyHeading, 2); - } + addTitle($"This is a very long title {i + 1}"); }); } @@ -49,11 +47,23 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Add TOC", () => { - for (var i = 0; i < 20; i++) - { - sidebar.AddToc($"This is a very long title {i + 1}", dummyHeading, i % 4 == 0 ? 2 : 3); - } + for (var i = 0; i < 10; i++) + addTitle($"This is a very long title {i + 1}", i % 4 != 0); }); } + + private void addTitle(string text, bool subtitle = false) + { + var headingBlock = createHeadingBlock(text, subtitle ? 3 : 2); + sidebar.AddToc(headingBlock, createHeading(headingBlock)); + } + + private HeadingBlock createHeadingBlock(string text, int level = 2) => new HeadingBlock(new HeadingBlockParser()) + { + Inline = new ContainerInline().AppendChild(new LiteralInline(text)), + Level = level, + }; + + private MarkdownHeading createHeading(HeadingBlock headingBlock) => new OsuMarkdownHeading(headingBlock); } } From a82eeb6daf15c2391a9c104ed2793c32958f20c7 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 16:00:26 +0700 Subject: [PATCH 21/44] tidy up sidebar test --- .../Visual/Online/TestSceneWikiSidebar.cs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs index a04a3eef6b..bf96fc86d9 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs @@ -6,7 +6,6 @@ using Markdig.Syntax; using Markdig.Syntax.Inlines; using NUnit.Framework; using osu.Framework.Allocation; -using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics.Containers.Markdown; using osu.Game.Overlays; using osu.Game.Overlays.Wiki; @@ -54,16 +53,13 @@ namespace osu.Game.Tests.Visual.Online private void addTitle(string text, bool subtitle = false) { - var headingBlock = createHeadingBlock(text, subtitle ? 3 : 2); - sidebar.AddToc(headingBlock, createHeading(headingBlock)); + var headingBlock = new HeadingBlock(new HeadingBlockParser()) + { + Inline = new ContainerInline().AppendChild(new LiteralInline(text)), + Level = subtitle ? 3 : 2, + }; + var heading = new OsuMarkdownHeading(headingBlock); + sidebar.AddToc(headingBlock, heading); } - - private HeadingBlock createHeadingBlock(string text, int level = 2) => new HeadingBlock(new HeadingBlockParser()) - { - Inline = new ContainerInline().AppendChild(new LiteralInline(text)), - Level = level, - }; - - private MarkdownHeading createHeading(HeadingBlock headingBlock) => new OsuMarkdownHeading(headingBlock); } } From 70c64af25e001ca8d097c2f12d4626e21bb39fdb Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 23:31:51 +0700 Subject: [PATCH 22/44] rename toc entry --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 0db4d41b8b..63a1ce3ffb 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -47,7 +47,7 @@ namespace osu.Game.Overlays.Wiki case 2: case 3: string title = getTitle(headingBlock.Inline); - tableOfContents.Add(new TocTitle(title, heading, headingBlock.Level == 3)); + tableOfContents.Add(new TableOfContentsEntry(title, heading, headingBlock.Level == 3)); break; } } @@ -69,7 +69,7 @@ namespace osu.Game.Overlays.Wiki return string.Empty; } - private class TocTitle : OsuHoverContainer + private class TableOfContentsEntry : OsuHoverContainer { [Resolved] private OverlayScrollContainer scrollContainer { get; set; } @@ -78,7 +78,7 @@ namespace osu.Game.Overlays.Wiki private readonly OsuTextFlowContainer textFlow; - public TocTitle(string text, MarkdownHeading target, bool subtitle = false) + public TableOfContentsEntry(string text, MarkdownHeading target, bool subtitle = false) { this.target = target; From 5febbe453086d874e0b893a8bca850867981492b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 23:32:42 +0700 Subject: [PATCH 23/44] rename method add entry --- osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs | 2 +- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 2 +- osu.Game/Overlays/Wiki/WikiSidebar.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs index bf96fc86d9..b4f1997bb0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs @@ -59,7 +59,7 @@ namespace osu.Game.Tests.Visual.Online Level = subtitle ? 3 : 2, }; var heading = new OsuMarkdownHeading(headingBlock); - sidebar.AddToc(headingBlock, heading); + sidebar.AddEntry(headingBlock, heading); } } } diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index 83a61db88d..60982b0aa9 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -52,7 +52,7 @@ namespace osu.Game.Overlays.Wiki Left = 30, Right = 50, }, - OnAddHeading = sidebar.AddToc, + OnAddHeading = sidebar.AddEntry, } }, }; diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 63a1ce3ffb..d4c484b0fd 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -40,7 +40,7 @@ namespace osu.Game.Overlays.Wiki }, }; - public void AddToc(HeadingBlock headingBlock, MarkdownHeading heading) + public void AddEntry(HeadingBlock headingBlock, MarkdownHeading heading) { switch (headingBlock.Level) { From a431ef6c4802c298c2b40bda1f4d658da7db1778 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 23:43:00 +0700 Subject: [PATCH 24/44] keep colour change when entry is clicked --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index d4c484b0fd..f2cb2c3100 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -74,6 +74,9 @@ namespace osu.Game.Overlays.Wiki [Resolved] private OverlayScrollContainer scrollContainer { get; set; } + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + private readonly MarkdownHeading target; private readonly OsuTextFlowContainer textFlow; @@ -100,7 +103,7 @@ namespace osu.Game.Overlays.Wiki protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load() { IdleColour = colourProvider.Light2; HoverColour = colourProvider.Light1; @@ -108,6 +111,7 @@ namespace osu.Game.Overlays.Wiki protected override bool OnClick(ClickEvent e) { + IdleColour = colourProvider.Light1; scrollContainer.ScrollTo(target); return base.OnClick(e); } From f07d4532d94f0f22f79408afdb517c3622c4d37e Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 23:48:27 +0700 Subject: [PATCH 25/44] move scroll to into action --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index f2cb2c3100..3de2c8addf 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -71,9 +71,6 @@ namespace osu.Game.Overlays.Wiki private class TableOfContentsEntry : OsuHoverContainer { - [Resolved] - private OverlayScrollContainer scrollContainer { get; set; } - [Resolved] private OverlayColourProvider colourProvider { get; set; } @@ -103,16 +100,16 @@ namespace osu.Game.Overlays.Wiki protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; [BackgroundDependencyLoader] - private void load() + private void load(OverlayScrollContainer scrollContainer) { IdleColour = colourProvider.Light2; HoverColour = colourProvider.Light1; + Action = () => scrollContainer.ScrollTo(target); } protected override bool OnClick(ClickEvent e) { IdleColour = colourProvider.Light1; - scrollContainer.ScrollTo(target); return base.OnClick(e); } } From 5ee77925e4ab345b93ccffde20a8e792d9fa4885 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 23:54:50 +0700 Subject: [PATCH 26/44] change WikiArticlePage to extends CompositeDrawable --- osu.Game/Overlays/Wiki/WikiArticlePage.cs | 63 ++++++++++++----------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs index 60982b0aa9..0061bff8ea 100644 --- a/osu.Game/Overlays/Wiki/WikiArticlePage.cs +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -10,7 +10,7 @@ using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays.Wiki { - public class WikiArticlePage : GridContainer + public class WikiArticlePage : CompositeDrawable { public Container SidebarContainer { get; } @@ -18,42 +18,47 @@ namespace osu.Game.Overlays.Wiki { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - }; - ColumnDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - }; WikiSidebar sidebar; - Content = new[] + InternalChild = new GridContainer { - new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + RowDimensions = new[] { - SidebarContainer = new Container + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + Content = new[] + { + new Drawable[] { - AutoSizeAxes = Axes.X, - Child = sidebar = new WikiSidebar(), - }, - new ArticleMarkdownContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - CurrentPath = currentPath, - Text = markdown, - DocumentMargin = new MarginPadding(0), - DocumentPadding = new MarginPadding + SidebarContainer = new Container { - Vertical = 20, - Left = 30, - Right = 50, + AutoSizeAxes = Axes.X, + Child = sidebar = new WikiSidebar(), }, - OnAddHeading = sidebar.AddEntry, - } + new ArticleMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + CurrentPath = currentPath, + Text = markdown, + DocumentMargin = new MarginPadding(0), + DocumentPadding = new MarginPadding + { + Vertical = 20, + Left = 30, + Right = 50, + }, + OnAddHeading = sidebar.AddEntry, + } + }, }, }; } From 4cf3381d0bcbe0d195890a16406fe6eaf5b21a72 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Fri, 4 Jun 2021 23:59:11 +0700 Subject: [PATCH 27/44] use wiki article page when failed fetch --- osu.Game/Overlays/WikiOverlay.cs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index 5beb5d50e6..fc24820f3c 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -11,7 +11,6 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Wiki; -using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays { @@ -139,20 +138,8 @@ namespace osu.Game.Overlays private void onFail() { - LoadDisplay(new WikiMarkdownContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - CurrentPath = $@"{api.WebsiteRootUrl}/wiki/", - Text = $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).", - DocumentMargin = new MarginPadding(0), - DocumentPadding = new MarginPadding - { - Vertical = 20, - Left = 30, - Right = 50, - }, - }); + LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/", + $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).")); } private void showParentPage() From c099751ad189f119dee015720753cf911debb623 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 5 Jun 2021 18:26:03 +0700 Subject: [PATCH 28/44] use plain if check in switch case --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index 3de2c8addf..c95ee3a8c3 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -61,8 +61,11 @@ namespace osu.Game.Overlays.Wiki case LiteralInline literalInline: return literalInline.Content.ToString(); - case LinkInline { IsImage: false } linkInline: - return getTitle(linkInline); + case LinkInline linkInline: + if (!linkInline.IsImage) + return getTitle(linkInline); + + break; } } From 958bddc8cb9d4443d729a6a54a0fb2bc5873e249 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 5 Jun 2021 18:30:28 +0700 Subject: [PATCH 29/44] remove onclick in toc entry --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index c95ee3a8c3..b4e97e4a7b 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -8,7 +8,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; -using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -109,12 +108,6 @@ namespace osu.Game.Overlays.Wiki HoverColour = colourProvider.Light1; Action = () => scrollContainer.ScrollTo(target); } - - protected override bool OnClick(ClickEvent e) - { - IdleColour = colourProvider.Light1; - return base.OnClick(e); - } } } } From 55f3a328a4bb7cb2e460261e242734bb44ad5eaa Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 5 Jun 2021 19:46:46 +0700 Subject: [PATCH 30/44] add WikiTableOfContents --- osu.Game/Overlays/Wiki/WikiTableOfContents.cs | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 osu.Game/Overlays/Wiki/WikiTableOfContents.cs diff --git a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs new file mode 100644 index 0000000000..857ec27020 --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs @@ -0,0 +1,108 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiTableOfContents : CompositeDrawable + { + private readonly FillFlowContainer content; + + private FillFlowContainer lastItem; + + private FillFlowContainer lastSubsection; + + public WikiTableOfContents() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = content = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }; + } + + public void AddEntry(string title, MarkdownHeading target, bool subtitle = false) + { + var entry = new TableOfContentsEntry(title, target, subtitle); + + if (subtitle) + { + lastSubsection ??= new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Left = 10 }, + }; + + lastSubsection.Add(entry); + + return; + } + + if (lastSubsection != null) + { + lastItem.Add(lastSubsection); + lastItem.Margin = new MarginPadding { Bottom = 10 }; + lastSubsection = null; + } + + content.Add(lastItem = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Margin = new MarginPadding { Bottom = 5 }, + Child = entry, + }); + } + + private class TableOfContentsEntry : OsuHoverContainer + { + [Resolved] + private OverlayColourProvider colourProvider { get; set; } + + private readonly MarkdownHeading target; + + private readonly OsuTextFlowContainer textFlow; + + public TableOfContentsEntry(string text, MarkdownHeading target, bool subtitle = false) + { + this.target = target; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Child = textFlow = new OsuTextFlowContainer(t => + { + t.Font = OsuFont.GetFont(size: subtitle ? 12 : 15); + }).With(f => + { + f.AddText(text); + f.RelativeSizeAxes = Axes.X; + f.AutoSizeAxes = Axes.Y; + }); + Margin = new MarginPadding { Bottom = 2 }; + } + + protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; + + [BackgroundDependencyLoader] + private void load(OverlayScrollContainer scrollContainer) + { + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Light1; + Action = () => scrollContainer.ScrollTo(target); + } + } + } +} From 9f45a2862358e98b9ba819dea5faec24dcd431b2 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sat, 5 Jun 2021 19:47:00 +0700 Subject: [PATCH 31/44] use WikiTableOfContents in WikiSidebar --- osu.Game/Overlays/Wiki/WikiSidebar.cs | 55 ++------------------------- 1 file changed, 4 insertions(+), 51 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs index b4e97e4a7b..ee4e195f3f 100644 --- a/osu.Game/Overlays/Wiki/WikiSidebar.cs +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -1,22 +1,19 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Collections.Generic; using Markdig.Syntax; using Markdig.Syntax.Inlines; -using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers.Markdown; using osu.Game.Graphics; -using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Wiki { public class WikiSidebar : OverlaySidebar { - private FillFlowContainer tableOfContents; + private WikiTableOfContents tableOfContents; protected override Drawable CreateContent() => new FillFlowContainer { @@ -29,13 +26,9 @@ namespace osu.Game.Overlays.Wiki { Text = "CONTENTS", Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Margin = new MarginPadding { Bottom = 5 }, }, - tableOfContents = new FillFlowContainer - { - Direction = FillDirection.Vertical, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - } + tableOfContents = new WikiTableOfContents(), }, }; @@ -45,8 +38,7 @@ namespace osu.Game.Overlays.Wiki { case 2: case 3: - string title = getTitle(headingBlock.Inline); - tableOfContents.Add(new TableOfContentsEntry(title, heading, headingBlock.Level == 3)); + tableOfContents.AddEntry(getTitle(headingBlock.Inline), heading, headingBlock.Level == 3); break; } } @@ -70,44 +62,5 @@ namespace osu.Game.Overlays.Wiki return string.Empty; } - - private class TableOfContentsEntry : OsuHoverContainer - { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - - private readonly MarkdownHeading target; - - private readonly OsuTextFlowContainer textFlow; - - public TableOfContentsEntry(string text, MarkdownHeading target, bool subtitle = false) - { - this.target = target; - - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Child = textFlow = new OsuTextFlowContainer(t => - { - t.Font = OsuFont.GetFont(size: subtitle ? 12 : 15); - }).With(f => - { - f.AddText(text); - f.RelativeSizeAxes = Axes.X; - f.AutoSizeAxes = Axes.Y; - }); - Margin = new MarginPadding { Top = subtitle ? 5 : 10 }; - Padding = new MarginPadding { Left = subtitle ? 10 : 0 }; - } - - protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; - - [BackgroundDependencyLoader] - private void load(OverlayScrollContainer scrollContainer) - { - IdleColour = colourProvider.Light2; - HoverColour = colourProvider.Light1; - Action = () => scrollContainer.ScrollTo(target); - } - } } } From 525c16419a5587a19a6173034e5d30e15ad2143b Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 6 Jun 2021 08:37:03 +0700 Subject: [PATCH 32/44] use container for main title and sub title table of contents --- osu.Game/Overlays/Wiki/WikiTableOfContents.cs | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs index 857ec27020..6c9f7d1536 100644 --- a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs +++ b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs @@ -15,9 +15,9 @@ namespace osu.Game.Overlays.Wiki { private readonly FillFlowContainer content; - private FillFlowContainer lastItem; + private Container lastMainTitle; - private FillFlowContainer lastSubsection; + private Container lastSubTitle; public WikiTableOfContents() { @@ -37,29 +37,26 @@ namespace osu.Game.Overlays.Wiki if (subtitle) { - lastSubsection ??= new FillFlowContainer + lastMainTitle.Margin = new MarginPadding(0); + + if (lastSubTitle != null) + lastSubTitle.Margin = new MarginPadding(0); + + content.Add(lastSubTitle = new Container { - Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding { Left = 10 }, - }; - - lastSubsection.Add(entry); + Margin = new MarginPadding { Bottom = 10 }, + Child = entry, + }); return; } - if (lastSubsection != null) - { - lastItem.Add(lastSubsection); - lastItem.Margin = new MarginPadding { Bottom = 10 }; - lastSubsection = null; - } + lastSubTitle = null; - content.Add(lastItem = new FillFlowContainer + content.Add(lastMainTitle = new Container { - Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Margin = new MarginPadding { Bottom = 5 }, @@ -92,6 +89,7 @@ namespace osu.Game.Overlays.Wiki f.AutoSizeAxes = Axes.Y; }); Margin = new MarginPadding { Bottom = 2 }; + Padding = new MarginPadding { Left = subtitle ? 10 : 0 }; } protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; From ed733ee648b91223a3d758d94bdaf90b3a2a6b11 Mon Sep 17 00:00:00 2001 From: Gagah Pangeran Rosfatiputra Date: Sun, 6 Jun 2021 20:19:39 +0700 Subject: [PATCH 33/44] directly using table of content entry in wiki table of contents --- osu.Game/Overlays/Wiki/WikiTableOfContents.cs | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs index 6c9f7d1536..77441c26ed 100644 --- a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs +++ b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs @@ -15,9 +15,9 @@ namespace osu.Game.Overlays.Wiki { private readonly FillFlowContainer content; - private Container lastMainTitle; + private TableOfContentsEntry lastMainTitle; - private Container lastSubTitle; + private TableOfContentsEntry lastSubTitle; public WikiTableOfContents() { @@ -42,26 +42,14 @@ namespace osu.Game.Overlays.Wiki if (lastSubTitle != null) lastSubTitle.Margin = new MarginPadding(0); - content.Add(lastSubTitle = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Bottom = 10 }, - Child = entry, - }); + content.Add(lastSubTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 10 })); return; } lastSubTitle = null; - content.Add(lastMainTitle = new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Margin = new MarginPadding { Bottom = 5 }, - Child = entry, - }); + content.Add(lastMainTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 5 })); } private class TableOfContentsEntry : OsuHoverContainer @@ -87,8 +75,8 @@ namespace osu.Game.Overlays.Wiki f.AddText(text); f.RelativeSizeAxes = Axes.X; f.AutoSizeAxes = Axes.Y; + f.Margin = new MarginPadding { Bottom = 2 }; }); - Margin = new MarginPadding { Bottom = 2 }; Padding = new MarginPadding { Left = subtitle ? 10 : 0 }; } From e606bf249afa83a73ebd9924886bced36afd9222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 7 Jun 2021 11:05:21 +0200 Subject: [PATCH 34/44] Move dependency specification to BDL As it is not used anywhere else. --- osu.Game/Overlays/Wiki/WikiTableOfContents.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs index 77441c26ed..c0615dce1f 100644 --- a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs +++ b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs @@ -54,9 +54,6 @@ namespace osu.Game.Overlays.Wiki private class TableOfContentsEntry : OsuHoverContainer { - [Resolved] - private OverlayColourProvider colourProvider { get; set; } - private readonly MarkdownHeading target; private readonly OsuTextFlowContainer textFlow; @@ -83,7 +80,7 @@ namespace osu.Game.Overlays.Wiki protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; [BackgroundDependencyLoader] - private void load(OverlayScrollContainer scrollContainer) + private void load(OverlayColourProvider colourProvider, OverlayScrollContainer scrollContainer) { IdleColour = colourProvider.Light2; HoverColour = colourProvider.Light1; From a0bda9ad595e48aabe2141359e2c38fdc3822188 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 7 Jun 2021 11:18:18 +0200 Subject: [PATCH 35/44] Hoist scroll cache declaration to original place of definition --- osu.Game/Overlays/OnlineOverlay.cs | 3 +++ osu.Game/Overlays/WikiOverlay.cs | 4 ---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/OnlineOverlay.cs b/osu.Game/Overlays/OnlineOverlay.cs index de33e4a1bc..a610511398 100644 --- a/osu.Game/Overlays/OnlineOverlay.cs +++ b/osu.Game/Overlays/OnlineOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -13,7 +14,9 @@ namespace osu.Game.Overlays { protected override Container Content => content; + [Cached] protected readonly OverlayScrollContainer ScrollFlow; + protected readonly LoadingLayer Loading; private readonly Container content; diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index fc24820f3c..bde73b6180 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -25,9 +25,6 @@ namespace osu.Game.Overlays [Resolved] private IAPIProvider api { get; set; } - [Cached] - private readonly OverlayScrollContainer scrollContainer; - private GetWikiRequest request; private CancellationTokenSource cancellationToken; @@ -39,7 +36,6 @@ namespace osu.Game.Overlays public WikiOverlay() : base(OverlayColourScheme.Orange, false) { - scrollContainer = ScrollFlow; } public void ShowPage(string pagePath = index_path) From c8e14d771033917af1b42339af7bdba0647e3fb1 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 8 Jun 2021 23:09:18 +0900 Subject: [PATCH 36/44] Ignore non-scorable and bonus judgements --- .../Visual/Gameplay/TestSceneHitErrorMeter.cs | 28 +++++++++++++++++++ .../HUD/HitErrorMeters/BarHitErrorMeter.cs | 3 ++ .../HUD/HitErrorMeters/ColourHitErrorMeter.cs | 9 +++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 2a12577ad8..7accaef818 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -109,6 +109,34 @@ namespace osu.Game.Tests.Visual.Gameplay meter => meter.ChildrenOfType().Count() == 2)); } + [Test] + public void TestBonus() + { + AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); + + AddStep("small bonus", () => newJudgement(result: HitResult.SmallBonus)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + + AddStep("large bonus", () => newJudgement(result: HitResult.LargeBonus)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + } + + [Test] + public void TestIgnore() + { + AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); + + AddStep("ignore hit", () => newJudgement(result: HitResult.IgnoreHit)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + + AddStep("ignore miss", () => newJudgement(result: HitResult.IgnoreMiss)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + } + private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) { hitWindows?.SetDifficulty(overallDifficulty); diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 0412085d1d..89f61785e8 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -217,6 +217,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0) return; + if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) + return; + if (judgementsContainer.Count > max_concurrent_judgements) { const double quick_fade_time = 100; diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 86c0de8855..dda2a6da95 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; using osuTK; using osuTK.Graphics; @@ -24,7 +25,13 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters InternalChild = judgementsFlow = new JudgementFlow(); } - protected override void OnNewJudgement(JudgementResult judgement) => judgementsFlow.Push(GetColourForHitResult(judgement.Type)); + protected override void OnNewJudgement(JudgementResult judgement) + { + if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) + return; + + judgementsFlow.Push(GetColourForHitResult(judgement.Type)); + } private class JudgementFlow : FillFlowContainer { From 00efed2c39d67d0d5f4c5b0d21509ebea2fef205 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 8 Jun 2021 23:10:21 +0900 Subject: [PATCH 37/44] Add colours for tick judgements --- osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 17a6e772fb..9844b9f10d 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { switch (result) { + case HitResult.SmallTickMiss: + case HitResult.LargeTickMiss: case HitResult.Miss: return colours.Red; @@ -53,6 +55,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters case HitResult.Good: return colours.GreenLight; + case HitResult.SmallTickHit: + case HitResult.LargeTickHit: case HitResult.Great: return colours.Blue; From 610cdaea98bb1fb9720035cfdbdaa113c542bed8 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 9 Jun 2021 16:14:55 +0900 Subject: [PATCH 38/44] Fix circle piece animation is sometimes not playing when a replay is rewound --- .../Skinning/Default/MainCirclePiece.cs | 21 +++++++++++-------- .../Skinning/Legacy/LegacyMainCirclePiece.cs | 17 ++++++++++----- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index fece3494e6..d7ebe9333d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs @@ -15,8 +15,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public class MainCirclePiece : CompositeDrawable { - public override bool RemoveCompletedTransforms => false; - private readonly CirclePiece circle; private readonly RingPiece ring; private readonly FlashPiece flash; @@ -44,7 +42,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); - private readonly IBindable armedState = new Bindable(); [Resolved] private DrawableHitObject drawableObject { get; set; } @@ -56,7 +53,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); - armedState.BindTo(drawableObject.State); } protected override void LoadComplete() @@ -72,19 +68,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); - armedState.BindValueChanged(animate, true); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableObject, drawableObject.State.Value); } - private void animate(ValueChangedEvent state) + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { - ClearTransforms(true); - using (BeginAbsoluteSequence(drawableObject.StateUpdateTime)) glow.FadeOut(400); using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { - switch (state.NewValue) + switch (state) { case ArmedState.Hit: const double flash_in = 40; @@ -111,5 +106,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default } } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableObject != null) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index e5200ac248..bb7a335efe 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -41,7 +41,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly Bindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); - private readonly IBindable armedState = new Bindable(); [Resolved] private DrawableHitObject drawableObject { get; set; } @@ -116,7 +115,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); - armedState.BindTo(drawableObject.State); Texture getTextureWithFallback(string name) { @@ -142,10 +140,11 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); - armedState.BindValueChanged(animate, true); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableObject, drawableObject.State.Value); } - private void animate(ValueChangedEvent state) + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { const double legacy_fade_duration = 240; @@ -153,7 +152,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { - switch (state.NewValue) + switch (state) { case ArmedState.Hit: circleSprites.FadeOut(legacy_fade_duration, Easing.Out); @@ -178,5 +177,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableObject != null) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } From 5418e895ae93b31f9515e7100a4a8136cd04756f Mon Sep 17 00:00:00 2001 From: ekrctb Date: Wed, 9 Jun 2021 16:50:13 +0900 Subject: [PATCH 39/44] Remove useless `ClearTransforms` The transforms are cleared by DHO before `ApplyCustomUpdateState` is invoked. --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index bb7a335efe..7a210324d7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -148,8 +148,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy { const double legacy_fade_duration = 240; - ClearTransforms(true); - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { switch (state) From a7ef0173e9a20f8827e2b9ede18221985fca0a3a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Jun 2021 17:07:28 +0900 Subject: [PATCH 40/44] Add safety to ensure background is correct tint when entering gameplay --- osu.Game/Screens/Play/Player.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 94e67107c9..f9036780aa 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -32,6 +32,7 @@ using osu.Game.Scoring.Legacy; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; +using osuTK.Graphics; namespace osu.Game.Screens.Play { @@ -856,6 +857,7 @@ namespace osu.Game.Screens.Play { b.IgnoreUserSettings.Value = false; b.BlurAmount.Value = 0; + b.FadeColour(Color4.White, 250); // bind component bindables. b.IsBreakTime.BindTo(breakTracker.IsBreakTime); From 258d05d1e0c8029cb8a28773804f828b0570f599 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Jun 2021 17:17:39 +0900 Subject: [PATCH 41/44] Ensure `PlayerLoader` restores the background colour to its own value on resume --- osu.Game/Screens/Play/PlayerLoader.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ce580e2b53..5f6b4ca2b0 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -184,8 +184,6 @@ namespace osu.Game.Screens.Play { if (epilepsyWarning != null) epilepsyWarning.DimmableBackground = b; - - b?.FadeColour(Color4.White, 800, Easing.OutQuint); }); Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); @@ -334,6 +332,8 @@ namespace osu.Game.Screens.Play content.FadeInFromZero(400); content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer); + + ApplyToBackground(b => b?.FadeColour(Color4.White, 800, Easing.OutQuint)); } private void contentOut() From 7b0c5e9d32528db538ee66775d40e96c2ca2b4d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Jun 2021 17:18:52 +0900 Subject: [PATCH 42/44] Fix results screen changing applied colour to background on exit The general rule is that screens should only apply colours and the likes on enter / resume, and leave the outwards transition to whatever screen is coming next. --- osu.Game/Screens/Ranking/ResultsScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index a0ea27b640..e460ee77f4 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Screens; using osu.Game.Audio; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; @@ -257,7 +258,7 @@ namespace osu.Game.Screens.Ranking ApplyToBackground(b => { b.BlurAmount.Value = BACKGROUND_BLUR; - b.FadeTo(0.5f, 250); + b.FadeColour(OsuColour.Gray(0.5f), 250); }); bottomPanel.FadeTo(1, 250); @@ -265,7 +266,6 @@ namespace osu.Game.Screens.Ranking public override bool OnExiting(IScreen next) { - ApplyToBackground(b => b.FadeTo(1, 250)); return base.OnExiting(next); } From a65b76bdbf3a360c7a9cb3c9d2f53dbbae35ad65 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Jun 2021 17:19:36 +0900 Subject: [PATCH 43/44] Add a simple fade to the results screen Stops it from immediately disappearing. --- osu.Game/Screens/Ranking/ResultsScreen.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index e460ee77f4..c44ce63ccb 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -266,8 +266,11 @@ namespace osu.Game.Screens.Ranking public override bool OnExiting(IScreen next) { + if (base.OnExiting(next)) + return true; - return base.OnExiting(next); + this.FadeOut(100); + return false; } public override bool OnBackButton() From f113c095ce55640dabac6b1c4ffc956b28a39839 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 9 Jun 2021 20:29:06 +0900 Subject: [PATCH 44/44] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 395470824f..cfa3bc836f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 9ecab1ee48..be10764c6a 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,7 +34,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index e66f125985..751f60912a 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - +