Use generated icons
This commit is contained in:
parent
b68d48e75c
commit
386e04dc49
7 changed files with 1647 additions and 37 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
51
examples/generate_icons.nim
Normal file
51
examples/generate_icons.nim
Normal 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
1450
examples/icons.nim
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue