Use generated icons

This commit is contained in:
Joey Yakimowich-Payne 2020-09-17 20:25:07 -06:00
commit 386e04dc49
7 changed files with 1647 additions and 37 deletions

View file

@ -1,5 +1,7 @@
import options
import os
import nanovg
import icons
type
StyleConfig* = ref object
@ -8,10 +10,19 @@ type
cornerRadiusBottomLeft*: float
cornerRadiusBottomRight*: float
paddingLeft*: float
paddingRight*: float
paddingBottom*: float
paddingTop*: float
icon*: Option[Icon]
iconFont*: string
fontBlur*: float
font*: string
fontSize*: float
fontColor*: Color
hasFontShadow*: bool
fontShadowColor*: Color
fontShadowXOffset*: float
fontShadowYOffset*: float
@ -26,8 +37,8 @@ type
highlightWidth*: float
fillColor*: Color
fillOverlay*: Paint
gradientStartColor*: Color
gradientEndColor*: Color
WindowConfig* = object
cornerRadiusTopLeft*: float
@ -35,27 +46,6 @@ type
cornerRadiusBottomLeft*: float
cornerRadiusBottomRight*: float
let DEFAULT_BUTTON_STYLE = StyleConfig(
cornerRadiusTopLeft: 3.0,
cornerRadiusTopRight: 3.0,
cornerRadiusBottomLeft: 3.0,
cornerRadiusBottomRight: 3.0,
fontBlur: 0.0,
font: "sans",
fontSize: 20.0,
fontColor: rgba(255, 255, 255, 160),
fontShadowColor: rgba(0, 0, 0, 60)
)
# To see icons in code, use a nerd font
const ICON_TRASH* = ""
const ICON_SEARCH* = "🔍"
const ICON_CIRCLED_CROSS* = "✖"
const ICON_CHEVRON_RIGHT* = "\uE75E"
const ICON_CHECK* = "✓"
const ICON_LOGIN* = "\uE740"
proc currentSourceDir*(): string {.inline.} =
return currentSourcePath.parentDir()
@ -136,6 +126,62 @@ proc cpToUtf8*(code: int): string =
return res
let Colors: tuple[Red, Green, Blue, Yellow, Orange, Purple, White, Grey, Black: Color] =
(
Red: rgb(231, 64, 74),
Green: rgb(40, 184, 115),
Blue: rgb(43, 183, 209),
Yellow: rgb(243, 203, 57),
Orange: rgb(255, 130, 76),
Purple: rgb(97, 18, 204),
White: rgb(255, 255, 255),
Grey: rgb(129, 110, 96),
Black: rgb(0, 0, 0)
)
proc defaultButtonStyle(fillColor: Color): StyleConfig {.inline.} =
StyleConfig(
cornerRadiusTopLeft: 3.0,
cornerRadiusTopRight: 3.0,
cornerRadiusBottomLeft: 3.0,
cornerRadiusBottomRight: 3.0,
paddingLeft: 10.0,
paddingRight: 10.0,
paddingTop: 5.0,
paddingBottom: 5.0,
iconFont: "fa",
fontBlur: 0.0,
font: "sans-bold",
fontSize: 20.0,
fontColor: rgba(255, 255, 255, 160),
hasFontShadow: true,
fontShadowColor: rgba(0, 0, 0, 160),
fontShadowXOffset: 0.0,
fontShadowYOffset: 1.0,
highlightColor: rgba(255, 255, 255, 100),
highlightWidth: 0.5,
hasShadow: true,
shadowColor: rgba(0, 0, 0, 90),
shadowXOffset: 3.0,
shadowYOffset: 3.0,
gradientStartColor: rgba(255, 255, 255, if fillColor.isBlack: 16 else: 32),
gradientEndColor: rgba(0, 0, 0, if fillColor.isBlack: 16 else: 32),
textAlignments: @[Alignment.Center, Alignment.Middle]
)
let DefaultButtonStyles: tuple[Red, Green, Blue, Yellow, Orange, Purple, White, Grey, Black: StyleConfig] =
(
Red: defaultButtonStyle(Colors.Red),
Green: defaultButtonStyle(Colors.Green),
Blue: defaultButtonStyle(Colors.Blue),
Yellow: defaultButtonStyle(Colors.Yellow),
Orange: defaultButtonStyle(Colors.Orange),
Purple: defaultButtonStyle(Colors.Purple),
White: defaultButtonStyle(Colors.White),
Grey: defaultButtonStyle(Colors.Grey),
Black: defaultButtonStyle(Colors.Black)
)
proc drawButton*(vg: Context, text: string, x, y, width, height: float) =
let bg = vg.linearGradient(
x, y, x, y+height,
@ -172,8 +218,69 @@ proc drawButton*(vg: Context, text: string, x, y, width, height: float) =
vg.pathLineTo(x+width-(radius), y+lightWidth+1)
vg.pathStroke()
proc drawButton*(vg: Context, text: string, x, y: float, style: StyleConfig = DefaultButtonStyles.Blue) =
proc drawButton*(vg: Context, preicon: string, text: string, x, y, w, h: float, color: Color) =
vg.setFontSize(style.fontSize)
vg.setFont(style.font)
let textBounds = vg.textBounds(text, 0.0, 0.0)
let textWidth = textBounds.horizontalAdvance
let height = (textBounds.bounds.ymax - textBounds.bounds.ymin) + style.paddingTop + style.paddingBottom
vg.setFontSize(height * 0.5)
vg.setFont(style.iconFont)
let iconBounds = vg.textBounds($style.icon, 0, 0)
var iconWidth = iconBounds.horizontalAdvance
# iconWidth += height*0.15
let width = textWidth + iconWidth + style.paddingLeft + style.paddingRight
let bg = vg.linearGradient(
x, y, x, y+height,
style.gradientStartColor,
style.gradientEndColor
)
let color = style.fillColor
let shadowColor = style.shadowColor
let lightWidth = style.highlightWidth
if style.hasShadow:
vg.beginPath()
vg.pathRoundedRect(
x+1+style.shadowXOffset,
y+1+style.shadowYOffset,
width-2, height-2,
style.cornerRadiusTopLeft, style.cornerRadiusTopRight,
style.cornerRadiusBottomRight, style.cornerRadiusBottomLeft
)
vg.setFillColor(style.shadowColor)
vg.pathFill()
vg.beginPath()
vg.pathRoundedRect(
x+1, y+1, width-2, height-2,
style.cornerRadiusTopLeft, style.cornerRadiusTopRight,
style.cornerRadiusBottomRight, style.cornerRadiusBottomLeft
)
vg.setFillColor(style.fillColor)
vg.pathFill()
vg.setFillPaint(bg)
vg.pathFill()
vg.beginPath()
vg.pathMoveTo(x+style.cornerRadiusBottomLeft, y+lightWidth+1)
vg.setStrokeWidth(lightWidth)
vg.setStrokeColor(style.highlightColor)
vg.pathLineTo(x+width-(style.cornerRadiusBottomLeft), y+lightWidth+1)
vg.pathStroke()
vg.setFont(style.font)
vg.textAlign(style.textAlignments)
vg.setFillColor(style.fontColor)
vg.text(text, x + width, y + height - 1)
proc drawButton*(vg: Context, preicon: Icon, text: string, x, y, w, h: float, color: Color) =
var
bg: Paint
@ -211,7 +318,7 @@ proc drawButton*(vg: Context, preicon: string, text: string, x, y, w, h: float,
vg.setFontSize(h*0.5)
vg.setFont("fa")
ib = vg.textBounds(preicon, 0, 0)
ib = vg.textBounds($preicon, 0, 0)
iw = ib.horizontalAdvance
iw += h*0.15
@ -219,7 +326,7 @@ proc drawButton*(vg: Context, preicon: string, text: string, x, y, w, h: float,
vg.setFont("fa")
vg.setFillColor(rgba(255,255,255,96))
vg.textAlign("left middle")
vg.text(preicon, x+w*0.5-tw*0.5-iw*0.75, y+h*0.5)
vg.text($preicon, x+w*0.5-tw*0.5-iw*0.75, y+h*0.5)
vg.setFontSize(20.0)
vg.setFont("sans-bold")
@ -242,7 +349,7 @@ proc drawSearchBox*(vg: Context, text: string, x, y, w, h: float) =
vg.setFont("icons")
vg.setFillColor(rgba(255,255,255,64))
vg.textAlign("center middle")
vg.text(ICON_SEARCH, x+h*0.55f, y+h*0.55f)
vg.text($Icon.Search, x+h*0.55f, y+h*0.55f)
vg.setFontSize(20.0f)
vg.setFont("sans")
@ -255,4 +362,4 @@ proc drawSearchBox*(vg: Context, text: string, x, y, w, h: float) =
vg.setFont("icons")
vg.setFillColor(rgba(255,255,255,32))
vg.textAlign("center middle")
vg.text(ICON_CIRCLED_CROSS, x+w-h*0.55f, y+h*0.55f)
vg.text($Icon.TimesCircle, x+w-h*0.55f, y+h*0.55f)

View file

@ -3,6 +3,7 @@ import nanovg
import glfw, glew
import perf
import common
import icons
proc frameBufferSize*(window: ptr Window): tuple[w, h: int32] =
var fbWidth, fbHeight: cint
@ -17,7 +18,6 @@ proc size*(window: ptr Window): tuple[w, h: int32] =
return (w: width, h: height)
proc main =
let
fps = newGraph(RenderStyle.FPS, "Frame Time")
cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
@ -67,9 +67,9 @@ proc main =
let x = vg.glyphPositions("Some仮名thing is up", 0, 0)
vg.drawWindow("Title", 50, 50, 300, 400)
vg.drawLabel("Hello!", 10, 10, 280, 20)
vg.drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
vg.drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton("Testing", 100, 300, 160, 28)
vg.drawButton(Icon.Trash, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
vg.drawButton(Icon.Trash, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton("Testing", 100, 300)
vg.render(fps, 5, 5)
vg.render(cpuGraph, 210, 5)

View file

@ -5,6 +5,7 @@ import os
import nanovg
import perf
import common
import icons
proc events(): bool =
result = false
@ -92,8 +93,8 @@ proc main() =
vg.text("Some仮名thing is up", 100, 100, 100)
vg.drawWindow("Title", 50, 50, 300, 400)
vg.drawLabel("Hello!", 10, 10, 280, 20)
vg.drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
vg.drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton(Icon.Trash, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
vg.drawButton(Icon.Trash, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton("Testing", 100, 300, 160, 28)
vg.render(fps, 5, 5)

View file

@ -6,6 +6,7 @@ import os
import nanovg
import perf
import common
import icons
proc events(): bool =
result = false
@ -114,8 +115,8 @@ proc main() =
vg.text("Some仮名thing is up", 100, 100, 100)
vg.drawWindow("Title", 50, 50, 300, 400)
vg.drawLabel("Hello!", 10, 10, 500, 20)
vg.drawButton(ICON_TRASH, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
vg.drawButton(ICON_TRASH, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton(Icon.Trash, "Delete", 100, 200, 160, 28, rgba(128, 16, 8, 255))
vg.drawButton(Icon.Trash, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton("Testing", 100, 300, 160, 28)
vg.drawSearchBox("Search...", 60, 400, 280, 25)

View file

@ -0,0 +1,51 @@
import os
import json, algorithm
import strutils, strformat
import httpcore
import httpclient
template camelCase(str: string, sep = '-'): string =
var res = newStringOfCap(str.len)
var i = 1
res.add(str[0].toUpperAscii)
while i < str.len:
if str[i] == sep and i < str.len - 1:
res.add(str[i+1].toUpperAscii)
i += 1
else:
res.add(str[i])
i += 1
res
proc main() =
const fontLicense {.strdefine.} = "free"
let url = "https://api.fontawesome.com/"
let client = newHttpClient()
let query = "{ \"query\": \"query { release(version:\\\"latest\\\") { icons(license:\\\"" & fontLicense & "\\\") {id, unicode} } }\" }"
let resp = client.request(url, HttpPost, body=query, headers = newHttpHeaders({"Content-type": "application/json"}))
let jsonStr = resp.body
let json = parseJson(jsonStr)
let icons = json{"data", "release", "icons"}
var res = """# NOTE: This file is autogenerated by generate_icons.nim
type
Icon* {.pure.} = enum
"""
if icons.isNil:
raise newException(CatchableError, "Icons is nil")
for icon in icons.getElems.sorted(proc (a, b: JsonNode): int = cmp(a["id"].to(string), b["id"].to(string))):
var id = icon["id"].to(string).camelCase()
if id[0] in {'0' .. '9'}:
id = "I" & id
let code = icon["unicode"].to(string).toUpperAscii
res.add(fmt" {id} = " & """"\u""" & code & "\"" & "\n")
writeFile(currentSourcePath().parentDir / "icons.nim", res)
when isMainModule:
main()

1450
examples/icons.nim Normal file

File diff suppressed because it is too large Load diff

View file

@ -73,7 +73,7 @@ cDefine("NANOVG_GL3", "")
cOverride:
# Standard Nim code to wrap types, consts, procs, etc.
type
NVGcolor* {.bycopy, importc: "struct NVGcolor".} = object
NVGcolor* {.bycopy, impnanovgHdr, importc: "struct NVGcolor".} = object
r*: cfloat
g*: cfloat
b*: cfloat