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 os
import nanovg import nanovg
import icons
type type
StyleConfig* = ref object StyleConfig* = ref object
@ -8,10 +10,19 @@ type
cornerRadiusBottomLeft*: float cornerRadiusBottomLeft*: float
cornerRadiusBottomRight*: float cornerRadiusBottomRight*: float
paddingLeft*: float
paddingRight*: float
paddingBottom*: float
paddingTop*: float
icon*: Option[Icon]
iconFont*: string
fontBlur*: float fontBlur*: float
font*: string font*: string
fontSize*: float fontSize*: float
fontColor*: Color fontColor*: Color
hasFontShadow*: bool
fontShadowColor*: Color fontShadowColor*: Color
fontShadowXOffset*: float fontShadowXOffset*: float
fontShadowYOffset*: float fontShadowYOffset*: float
@ -26,8 +37,8 @@ type
highlightWidth*: float highlightWidth*: float
fillColor*: Color fillColor*: Color
fillOverlay*: Paint gradientStartColor*: Color
gradientEndColor*: Color
WindowConfig* = object WindowConfig* = object
cornerRadiusTopLeft*: float cornerRadiusTopLeft*: float
@ -35,27 +46,6 @@ type
cornerRadiusBottomLeft*: float cornerRadiusBottomLeft*: float
cornerRadiusBottomRight*: 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.} = proc currentSourceDir*(): string {.inline.} =
return currentSourcePath.parentDir() return currentSourcePath.parentDir()
@ -136,6 +126,62 @@ proc cpToUtf8*(code: int): string =
return res 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) = proc drawButton*(vg: Context, text: string, x, y, width, height: float) =
let bg = vg.linearGradient( let bg = vg.linearGradient(
x, y, x, y+height, 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.pathLineTo(x+width-(radius), y+lightWidth+1)
vg.pathStroke() 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 var
bg: Paint 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.setFontSize(h*0.5)
vg.setFont("fa") vg.setFont("fa")
ib = vg.textBounds(preicon, 0, 0) ib = vg.textBounds($preicon, 0, 0)
iw = ib.horizontalAdvance iw = ib.horizontalAdvance
iw += h*0.15 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.setFont("fa")
vg.setFillColor(rgba(255,255,255,96)) vg.setFillColor(rgba(255,255,255,96))
vg.textAlign("left middle") 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.setFontSize(20.0)
vg.setFont("sans-bold") vg.setFont("sans-bold")
@ -242,7 +349,7 @@ proc drawSearchBox*(vg: Context, text: string, x, y, w, h: float) =
vg.setFont("icons") vg.setFont("icons")
vg.setFillColor(rgba(255,255,255,64)) vg.setFillColor(rgba(255,255,255,64))
vg.textAlign("center middle") 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.setFontSize(20.0f)
vg.setFont("sans") vg.setFont("sans")
@ -255,4 +362,4 @@ proc drawSearchBox*(vg: Context, text: string, x, y, w, h: float) =
vg.setFont("icons") vg.setFont("icons")
vg.setFillColor(rgba(255,255,255,32)) vg.setFillColor(rgba(255,255,255,32))
vg.textAlign("center middle") 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 glfw, glew
import perf import perf
import common import common
import icons
proc frameBufferSize*(window: ptr Window): tuple[w, h: int32] = proc frameBufferSize*(window: ptr Window): tuple[w, h: int32] =
var fbWidth, fbHeight: cint var fbWidth, fbHeight: cint
@ -17,7 +18,6 @@ proc size*(window: ptr Window): tuple[w, h: int32] =
return (w: width, h: height) return (w: width, h: height)
proc main = proc main =
let let
fps = newGraph(RenderStyle.FPS, "Frame Time") fps = newGraph(RenderStyle.FPS, "Frame Time")
cpuGraph = newGraph(RenderStyle.MS, "CPU Time") cpuGraph = newGraph(RenderStyle.MS, "CPU Time")
@ -67,9 +67,9 @@ proc main =
let x = vg.glyphPositions("Some仮名thing is up", 0, 0) let x = vg.glyphPositions("Some仮名thing is up", 0, 0)
vg.drawWindow("Title", 50, 50, 300, 400) vg.drawWindow("Title", 50, 50, 300, 400)
vg.drawLabel("Hello!", 10, 10, 280, 20) 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, "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, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton("Testing", 100, 300, 160, 28) vg.drawButton("Testing", 100, 300)
vg.render(fps, 5, 5) vg.render(fps, 5, 5)
vg.render(cpuGraph, 210, 5) vg.render(cpuGraph, 210, 5)

View file

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

View file

@ -6,6 +6,7 @@ import os
import nanovg import nanovg
import perf import perf
import common import common
import icons
proc events(): bool = proc events(): bool =
result = false result = false
@ -114,8 +115,8 @@ proc main() =
vg.text("Some仮名thing is up", 100, 100, 100) vg.text("Some仮名thing is up", 100, 100, 100)
vg.drawWindow("Title", 50, 50, 300, 400) vg.drawWindow("Title", 50, 50, 300, 400)
vg.drawLabel("Hello!", 10, 10, 500, 20) 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, "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, "Deleter", 100, 250, 160, 28, rgba(12, 130, 80, 255))
vg.drawButton("Testing", 100, 300, 160, 28) vg.drawButton("Testing", 100, 300, 160, 28)
vg.drawSearchBox("Search...", 60, 400, 280, 25) 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: cOverride:
# Standard Nim code to wrap types, consts, procs, etc. # Standard Nim code to wrap types, consts, procs, etc.
type type
NVGcolor* {.bycopy, importc: "struct NVGcolor".} = object NVGcolor* {.bycopy, impnanovgHdr, importc: "struct NVGcolor".} = object
r*: cfloat r*: cfloat
g*: cfloat g*: cfloat
b*: cfloat b*: cfloat