-
-
Notifications
You must be signed in to change notification settings - Fork 12
Named Avalonia colors: an example of listing and sorting them by color channel #270
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,169 @@ | ||
| namespace Gallery | ||
|
|
||
| open System | ||
| open System.Diagnostics | ||
| open System.Reflection | ||
| open Avalonia.Layout | ||
| open Avalonia.Media | ||
| open Fabulous | ||
| open Fabulous.Avalonia | ||
|
|
||
| (* Are these builders worth including into Fabulous.Avalonia in one form or the other? | ||
| Otherwise - how to create empty HWraps or VWraps for itemsPanel() extensions like below? *) | ||
| [<AutoOpen>] | ||
| module EmptyWrapPanelBuilders = | ||
| type Fabulous.Avalonia.View with | ||
|
|
||
| /// <summary>Creates a <see cref="WrapPanel" /> with <see cref="WrapPanel.Orientation" /> set to <see cref="Orientation.Vertical" /> | ||
| /// rendering child elements from left to right while they fit the width and starting a new line when there is no space left | ||
| /// (including any margins and borders). See <seealso href="https://docs.avaloniaui.net/docs/reference/controls/detailed-reference/wrappanel" />.</summary> | ||
| static member EmptyVWrap() = | ||
| WidgetBuilder<'msg, IFabPanel>(WrapPanel.WidgetKey, WrapPanel.Orientation.WithValue(Orientation.Vertical)) | ||
|
|
||
| /// <summary>Creates a <see cref="WrapPanel" /> with <see cref="WrapPanel.Orientation" /> set to <see cref="Orientation.Horizontal" /> | ||
| /// rendering child elements from top to bottom while they fit the height and starting a new column when there is no space left | ||
| /// (including any margins and borders). See <seealso href="https://docs.avaloniaui.net/docs/reference/controls/detailed-reference/wrappanel" />.</summary> | ||
| static member EmptyHWrap() = | ||
| WidgetBuilder<'msg, IFabPanel>(WrapPanel.WidgetKey, WrapPanel.Orientation.WithValue(Orientation.Horizontal)) | ||
|
|
||
| open type Fabulous.Avalonia.View | ||
|
|
||
| module ColorsByChannel = | ||
| type ColorInfo = | ||
| { Name: string | ||
| Color: Color | ||
| Hsv: HsvColor | ||
| Hsl: HslColor } | ||
|
|
||
| type SortOption = | ||
| | R = 0 | ||
| | G = 1 | ||
| | B = 2 | ||
| | H = 3 | ||
| | Sl = 4 | ||
| | Sv = 5 | ||
| | L = 6 | ||
| | V = 7 | ||
| | A = 8 | ||
|
|
||
| type Model = | ||
| { AllColors: ColorInfo list option | ||
| SortOptions: SortOption list | ||
| SortBy: SortOption } | ||
|
|
||
| type Msg = | ||
| | ExpandingColors | ||
| | SortBy of SortOption | ||
|
|
||
| let private getSortStrategy sortBy : (ColorInfo -> float) = | ||
| match sortBy with | ||
| | SortOption.R -> fun c -> float c.Color.R | ||
| | SortOption.G -> fun c -> float c.Color.G | ||
| | SortOption.B -> fun c -> float c.Color.B | ||
| | SortOption.H -> _.Hsl.H | ||
| | SortOption.Sl -> _.Hsl.S | ||
| | SortOption.Sv -> _.Hsv.S | ||
| | SortOption.L -> _.Hsl.L | ||
| | SortOption.V -> _.Hsv.V | ||
| | SortOption.A -> _.Hsl.A | ||
| | _ -> failwith "unknown sort option" | ||
|
|
||
| let private getStaticProperties<'T> () = | ||
| typeof<'T> | ||
| .GetProperties(BindingFlags.Public ||| BindingFlags.Static) | ||
|
|
||
| let private loadColors () = | ||
| getStaticProperties<Colors>() | ||
| |> Seq.map(fun prop -> | ||
| let color = prop.GetValue(null) |> unbox<Color> | ||
|
|
||
| { Name = prop.Name | ||
| Color = color | ||
| Hsl = color.ToHsl() | ||
| Hsv = color.ToHsv() }) | ||
|
|
||
| let private init () = | ||
| { AllColors = None | ||
| SortOptions = Enum.GetValues<SortOption>() |> List.ofSeq | ||
| SortBy = SortOption.L }, | ||
| Cmd.none | ||
|
|
||
| let private update msg model = | ||
| match msg with | ||
| | ExpandingColors -> | ||
| let model = | ||
| if model.AllColors.IsSome then | ||
| model | ||
| else | ||
| { model with | ||
| AllColors = loadColors() |> Seq.sortBy(getSortStrategy model.SortBy) |> List.ofSeq |> Some } | ||
|
|
||
| model, Cmd.none | ||
|
|
||
| | SortBy option -> | ||
| { model with | ||
| SortBy = option | ||
| AllColors = | ||
| match model.AllColors with | ||
| | Some value -> value |> List.sortBy(getSortStrategy option) |> Some | ||
| | None -> None }, | ||
| Cmd.none | ||
|
|
||
| let private displaySortBy sortBy = | ||
| match sortBy with | ||
| | SortOption.Sl -> "S (HSL)" | ||
| | SortOption.Sv -> "S (HSV)" | ||
| | _ -> sortBy.ToString() | ||
|
|
||
| let private program = | ||
| Program.statefulWithCmd init update | ||
| |> Program.withTrace(fun (format, args) -> Debug.WriteLine(format, box args)) | ||
| |> Program.withExceptionHandler(fun ex -> | ||
| #if DEBUG | ||
| printfn $"Exception: %s{ex.ToString()}" | ||
| false | ||
| #else | ||
| true | ||
| #endif | ||
| ) | ||
|
|
||
| (* may also/alternatively be used as a show case for | ||
| horizontal ListBox, horizontal ItemsControl, | ||
| lazy-loaded Expander, WrapPanel or ThemeAware *) | ||
| let view () = | ||
| Component("ColorsByChannel") { | ||
| let! model = Context.Mvu program | ||
|
|
||
| Expander( | ||
| "Named Avalonia UI Colors", | ||
| VStack(5) { | ||
| HStack(5) { | ||
| TextBlock("Sort by channel") | ||
| .verticalAlignment(VerticalAlignment.Center) | ||
|
|
||
| ListBox(model.SortOptions, (fun s -> TextBlock(displaySortBy s))) | ||
| .selectedItem(model.SortBy) | ||
| .onSelectionChanged(fun args -> | ||
| let o = unbox<SortOption>(args.AddedItems.Item 0) | ||
| SortBy o) | ||
| .itemsPanel(EmptyHWrap()) | ||
| } | ||
|
|
||
| ScrollViewer( | ||
| ItemsControl( | ||
| model.AllColors |> Option.defaultValue [], | ||
| fun c -> | ||
| Border( | ||
| Border(TextBlock(c.Name)) | ||
| .background(ThemeAware.With(Colors.White, Colors.Black)) | ||
| ) | ||
| .padding(50, 20, 0, 0) | ||
| .background(c.Color) | ||
| ) | ||
| .itemsPanel(EmptyHWrap()) | ||
| ) | ||
| } | ||
| ) | ||
| .maxWidth(600) | ||
| .onExpanding(fun _ -> ExpandingColors) | ||
| } | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.