mirror of
https://github.com/IllusionMan1212/libui-ng-odin.git
synced 2026-10-24 02:12:37 +00:00
initial commit
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
ols.json
|
||||||
|
|
||||||
|
# Ignore examples dir
|
||||||
|
examples/
|
||||||
|
# But Unignore .odin files in it
|
||||||
|
examples/!*.odin
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
Copyright 2024 - IllusionMan1212
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# libui-ng Odin Bindings
|
||||||
|
Handwritten Odin bindings for [libui-ng](https://github.com/libui-ng/libui-ng/)
|
||||||
|
Based on upstream commit: 49b04c4cf8ae4d3e38e389f446ef75170eb62762
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
The upstream examples have been reimplemented using Odin and they work identical to the originals (with the exception of the multithreaded example)
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
- [ ] Support and test Windows
|
||||||
|
- [ ] Support and test Mac?
|
||||||
|
|
||||||
@@ -0,0 +1,307 @@
|
|||||||
|
package libui_controlgallery
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.Quit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
onShouldQuit :: proc "c" (data: rawptr) -> b32 {
|
||||||
|
mainwin = transmute(^libui.Window)data
|
||||||
|
|
||||||
|
libui.ControlDestroy(cast(^libui.Control)mainwin)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
makeBasicControlsPage :: proc() -> ^libui.Control {
|
||||||
|
vbox := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
|
||||||
|
hbox := libui.NewHorizontalBox()
|
||||||
|
libui.BoxSetPadded(hbox, true)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)hbox, false)
|
||||||
|
|
||||||
|
libui.BoxAppend(hbox,
|
||||||
|
cast(^libui.Control)libui.NewButton("Button"),
|
||||||
|
false)
|
||||||
|
libui.BoxAppend(hbox,
|
||||||
|
cast(^libui.Control)libui.NewCheckbox("Checkbox"),
|
||||||
|
false)
|
||||||
|
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewLabel("This is a label.\nLabels can span multiple lines."),
|
||||||
|
false)
|
||||||
|
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewHorizontalSeparator(),
|
||||||
|
false)
|
||||||
|
|
||||||
|
group := libui.NewGroup("Entries")
|
||||||
|
libui.GroupSetMargined(group, true)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)group, true)
|
||||||
|
|
||||||
|
entryForm := libui.NewForm()
|
||||||
|
libui.FormSetPadded(entryForm, true)
|
||||||
|
libui.GroupSetChild(group, cast(^libui.Control)entryForm)
|
||||||
|
|
||||||
|
libui.FormAppend(entryForm,
|
||||||
|
"Entry",
|
||||||
|
cast(^libui.Control)libui.NewEntry(),
|
||||||
|
false)
|
||||||
|
libui.FormAppend(entryForm,
|
||||||
|
"Password Entry",
|
||||||
|
cast(^libui.Control)libui.NewPasswordEntry(),
|
||||||
|
false)
|
||||||
|
libui.FormAppend(entryForm,
|
||||||
|
"Search Entry",
|
||||||
|
cast(^libui.Control)libui.NewSearchEntry(),
|
||||||
|
false)
|
||||||
|
libui.FormAppend(entryForm,
|
||||||
|
"Multiline Entry",
|
||||||
|
cast(^libui.Control)libui.NewMultilineEntry(),
|
||||||
|
true)
|
||||||
|
libui.FormAppend(entryForm,
|
||||||
|
"Multiline Entry No Wrap",
|
||||||
|
cast(^libui.Control)libui.NewNonWrappingMultilineEntry(),
|
||||||
|
true)
|
||||||
|
|
||||||
|
return cast(^libui.Control)vbox
|
||||||
|
}
|
||||||
|
|
||||||
|
spinbox: ^libui.Spinbox
|
||||||
|
slider: ^libui.Slider
|
||||||
|
pbar: ^libui.ProgressBar
|
||||||
|
|
||||||
|
onSpinboxChanged :: proc "c" (s: ^libui.Spinbox, data: rawptr) {
|
||||||
|
libui.SliderSetValue(slider, libui.SpinboxValue(s))
|
||||||
|
libui.ProgressBarSetValue(pbar, libui.SpinboxValue(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
onSliderChanged :: proc "c" (s: ^libui.Slider, data: rawptr) {
|
||||||
|
libui.SpinboxSetValue(spinbox, libui.SliderValue(s))
|
||||||
|
libui.ProgressBarSetValue(pbar, libui.SliderValue(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
makeNumbersPage :: proc() -> ^libui.Control {
|
||||||
|
hbox := libui.NewHorizontalBox()
|
||||||
|
libui.BoxSetPadded(hbox, true)
|
||||||
|
|
||||||
|
group := libui.NewGroup("Numbers")
|
||||||
|
libui.GroupSetMargined(group, true)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)group, true)
|
||||||
|
|
||||||
|
vbox := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
libui.GroupSetChild(group, cast(^libui.Control)vbox)
|
||||||
|
|
||||||
|
spinbox = libui.NewSpinbox(0, 100)
|
||||||
|
slider = libui.NewSlider(0, 100)
|
||||||
|
pbar = libui.NewProgressBar()
|
||||||
|
libui.SpinboxOnChanged(spinbox, onSpinboxChanged, nil)
|
||||||
|
libui.SliderOnChanged(slider, onSliderChanged, nil)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)spinbox, false)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)slider, false)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)pbar, false)
|
||||||
|
|
||||||
|
ip := libui.NewProgressBar()
|
||||||
|
libui.ProgressBarSetValue(ip, -1)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)ip, false)
|
||||||
|
|
||||||
|
group = libui.NewGroup("Lists")
|
||||||
|
libui.GroupSetMargined(group, true)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)group, true)
|
||||||
|
|
||||||
|
vbox = libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
libui.GroupSetChild(group, cast(^libui.Control)vbox)
|
||||||
|
|
||||||
|
cbox := libui.NewCombobox()
|
||||||
|
libui.ComboboxAppend(cbox, "Combobox Item 1")
|
||||||
|
libui.ComboboxAppend(cbox, "Combobox Item 2")
|
||||||
|
libui.ComboboxAppend(cbox, "Combobox Item 3")
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)cbox, false)
|
||||||
|
|
||||||
|
ecbox := libui.NewEditableCombobox()
|
||||||
|
libui.EditableComboboxAppend(ecbox, "Editable Item 1")
|
||||||
|
libui.EditableComboboxAppend(ecbox, "Editable Item 2")
|
||||||
|
libui.EditableComboboxAppend(ecbox, "Editable Item 3")
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)ecbox, false)
|
||||||
|
|
||||||
|
rb := libui.NewRadioButtons()
|
||||||
|
libui.RadioButtonsAppend(rb, "Radio Button 1")
|
||||||
|
libui.RadioButtonsAppend(rb, "Radio Button 2")
|
||||||
|
libui.RadioButtonsAppend(rb, "Radio Button 3")
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)rb, false)
|
||||||
|
|
||||||
|
return cast(^libui.Control)hbox
|
||||||
|
}
|
||||||
|
|
||||||
|
mainwin: ^libui.Window
|
||||||
|
|
||||||
|
onOpenFileClicked :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
entry := transmute(^libui.Entry)data
|
||||||
|
|
||||||
|
filename := libui.OpenFile(mainwin)
|
||||||
|
if filename == nil {
|
||||||
|
libui.EntrySetText(entry, "(cancelled)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
libui.EntrySetText(entry, filename)
|
||||||
|
libui.FreeText(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpenFolderClicked :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
entry := transmute(^libui.Entry)data
|
||||||
|
|
||||||
|
filename := libui.OpenFolder(mainwin)
|
||||||
|
if filename == nil {
|
||||||
|
libui.EntrySetText(entry, "(cancelled)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
libui.EntrySetText(entry, filename)
|
||||||
|
libui.FreeText(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
onSaveFileClicked :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
entry := transmute(^libui.Entry)data
|
||||||
|
|
||||||
|
filename := libui.SaveFile(mainwin)
|
||||||
|
if filename == nil {
|
||||||
|
libui.EntrySetText(entry, "(cancelled)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
libui.EntrySetText(entry, filename)
|
||||||
|
libui.FreeText(filename)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgBoxClicked :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
libui.MsgBox(mainwin, "This is a normal message box.", "More detailed information can be shown here.")
|
||||||
|
}
|
||||||
|
|
||||||
|
onMsgBoxErrorClicked :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
libui.MsgBoxError(mainwin, "This message box describes an error.", "More detailed information can be shown here.")
|
||||||
|
}
|
||||||
|
|
||||||
|
makeDataChoosersPage :: proc() -> ^libui.Control {
|
||||||
|
hbox := libui.NewHorizontalBox()
|
||||||
|
libui.BoxSetPadded(hbox, true)
|
||||||
|
|
||||||
|
vbox := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)vbox, false)
|
||||||
|
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewDatePicker(),
|
||||||
|
false)
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewTimePicker(),
|
||||||
|
false)
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewDateTimePicker(),
|
||||||
|
false)
|
||||||
|
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewFontButton(),
|
||||||
|
false)
|
||||||
|
libui.BoxAppend(vbox,
|
||||||
|
cast(^libui.Control)libui.NewColorButton(),
|
||||||
|
false)
|
||||||
|
|
||||||
|
libui.BoxAppend(hbox,
|
||||||
|
cast(^libui.Control)libui.NewVerticalSeparator(),
|
||||||
|
false)
|
||||||
|
|
||||||
|
vbox = libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)vbox, true)
|
||||||
|
|
||||||
|
grid := libui.NewGrid()
|
||||||
|
libui.GridSetPadded(grid, true)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)grid, false)
|
||||||
|
|
||||||
|
button := libui.NewButton(" Open File ")
|
||||||
|
entry := libui.NewEntry()
|
||||||
|
libui.EntrySetReadOnly(entry, true)
|
||||||
|
libui.ButtonOnClicked(button, onOpenFileClicked, entry)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)button,
|
||||||
|
0, 0, 1, 1,
|
||||||
|
false, .Fill, false, .Fill)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)entry,
|
||||||
|
1, 0, 1, 1,
|
||||||
|
true, .Fill, false, .Fill)
|
||||||
|
|
||||||
|
button = libui.NewButton("Open Folder")
|
||||||
|
entry = libui.NewEntry()
|
||||||
|
libui.EntrySetReadOnly(entry, true)
|
||||||
|
libui.ButtonOnClicked(button, onOpenFolderClicked, entry)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)button,
|
||||||
|
0, 1, 1, 1,
|
||||||
|
false, .Fill, false, .Fill)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)entry,
|
||||||
|
1, 1, 1, 1,
|
||||||
|
true, .Fill, false, .Fill)
|
||||||
|
|
||||||
|
button = libui.NewButton(" Save File ")
|
||||||
|
entry = libui.NewEntry()
|
||||||
|
libui.EntrySetReadOnly(entry, true)
|
||||||
|
libui.ButtonOnClicked(button, onSaveFileClicked, entry)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)button,
|
||||||
|
0, 2, 1, 1,
|
||||||
|
false, .Fill, false, .Fill)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)entry,
|
||||||
|
1, 2, 1, 1,
|
||||||
|
true, .Fill, false, .Fill)
|
||||||
|
|
||||||
|
msggrid := libui.NewGrid()
|
||||||
|
libui.GridSetPadded(msggrid, true)
|
||||||
|
libui.GridAppend(grid, cast(^libui.Control)msggrid,
|
||||||
|
0, 3, 2, 1,
|
||||||
|
false, .Center, false, .Start)
|
||||||
|
|
||||||
|
button = libui.NewButton("Message Box")
|
||||||
|
libui.ButtonOnClicked(button, onMsgBoxClicked, nil)
|
||||||
|
libui.GridAppend(msggrid, cast(^libui.Control)button,
|
||||||
|
0, 0, 1, 1,
|
||||||
|
false, .Fill, false, .Fill)
|
||||||
|
button = libui.NewButton("Error Box")
|
||||||
|
libui.ButtonOnClicked(button, onMsgBoxErrorClicked, nil)
|
||||||
|
libui.GridAppend(msggrid, cast(^libui.Control)button,
|
||||||
|
1, 0, 1, 1,
|
||||||
|
false, .Fill, false, .Fill)
|
||||||
|
|
||||||
|
return cast(^libui.Control)hbox
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
options: libui.InitOptions
|
||||||
|
|
||||||
|
err := libui.Init(&options)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintln("error initializing libui: %s", err)
|
||||||
|
libui.FreeInitError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
mainwin = libui.NewWindow("libui Control Gallery", 640, 480, true)
|
||||||
|
libui.WindowOnClosing(mainwin, onClosing, nil)
|
||||||
|
libui.OnShouldQuit(onShouldQuit, mainwin)
|
||||||
|
|
||||||
|
tab := libui.NewTab()
|
||||||
|
libui.WindowSetChild(mainwin, cast(^libui.Control)tab)
|
||||||
|
libui.WindowSetMargined(mainwin, true)
|
||||||
|
|
||||||
|
libui.TabAppend(tab, "Basic Controls", makeBasicControlsPage())
|
||||||
|
libui.TabSetMargined(tab, 0, true)
|
||||||
|
|
||||||
|
libui.TabAppend(tab, "Numbers and Lists", makeNumbersPage())
|
||||||
|
libui.TabSetMargined(tab, 1, true)
|
||||||
|
|
||||||
|
libui.TabAppend(tab, "Data Choosers", makeDataChoosersPage())
|
||||||
|
libui.TabSetMargined(tab, 2, true)
|
||||||
|
|
||||||
|
libui.ControlShow(cast(^libui.Control)mainwin)
|
||||||
|
libui.Main()
|
||||||
|
}
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
package libui_datetime
|
||||||
|
|
||||||
|
import "base:runtime"
|
||||||
|
import "core:fmt"
|
||||||
|
import "core:c/libc"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
dtboth, dtdate, dttime: ^libui.DateTimePicker
|
||||||
|
|
||||||
|
timeFormat :: proc(d: ^libui.DateTimePicker) -> cstring {
|
||||||
|
if d == dtboth {
|
||||||
|
return "%c"
|
||||||
|
} else if d == dtdate {
|
||||||
|
return "%x"
|
||||||
|
} else if d == dttime {
|
||||||
|
return "%X"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
onChanged :: proc "c" (d: ^libui.DateTimePicker, data: rawptr) {
|
||||||
|
context = runtime.default_context()
|
||||||
|
time: libc.tm
|
||||||
|
buf: [64]i8
|
||||||
|
|
||||||
|
libui.DateTimePickerTime(d, &time)
|
||||||
|
libc.strftime(cast([^]u8)&buf, size_of(buf), timeFormat(d), &time)
|
||||||
|
libui.LabelSetText(transmute(^libui.Label)data, transmute(cstring)&buf[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
onClicked :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
t: libc.time_t
|
||||||
|
tmbuf: libc.tm
|
||||||
|
|
||||||
|
now := cast(bool)transmute(int)data
|
||||||
|
t = 0
|
||||||
|
if (now) {
|
||||||
|
t = libc.time(nil)
|
||||||
|
}
|
||||||
|
tmbuf = libc.localtime(&t)^
|
||||||
|
|
||||||
|
if (now) {
|
||||||
|
libui.DateTimePickerSetTime(dtdate, tmbuf)
|
||||||
|
libui.DateTimePickerSetTime(dttime, tmbuf)
|
||||||
|
} else {
|
||||||
|
libui.DateTimePickerSetTime(dtboth, tmbuf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.Quit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
o: libui.InitOptions
|
||||||
|
g: ^libui.Grid
|
||||||
|
l: ^libui.Label
|
||||||
|
b: ^libui.Button
|
||||||
|
|
||||||
|
err := libui.Init(&o)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintln("error initializing ui: %s", err)
|
||||||
|
libui.FreeInitError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w := libui.NewWindow("Date / Time", 320, 240, false)
|
||||||
|
libui.WindowSetMargined(w, true)
|
||||||
|
|
||||||
|
g = libui.NewGrid()
|
||||||
|
libui.GridSetPadded(g, true)
|
||||||
|
libui.WindowSetChild(w, cast(^libui.Control)g)
|
||||||
|
|
||||||
|
dtboth = libui.NewDateTimePicker()
|
||||||
|
dtdate = libui.NewDatePicker()
|
||||||
|
dttime = libui.NewTimePicker()
|
||||||
|
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)dtboth,
|
||||||
|
0, 0, 2, 1,
|
||||||
|
true, .Fill, false, .Fill)
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)dtdate,
|
||||||
|
0, 1, 1, 1,
|
||||||
|
true, .Fill, false, .Fill)
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)dttime,
|
||||||
|
1, 1, 1, 1,
|
||||||
|
true, .Fill, false, .Fill)
|
||||||
|
|
||||||
|
l = libui.NewLabel("")
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)l,
|
||||||
|
0, 2, 2, 1,
|
||||||
|
true, .Center, false, .Fill)
|
||||||
|
libui.DateTimePickerOnChanged(dtboth, onChanged, l)
|
||||||
|
l = libui.NewLabel("")
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)l,
|
||||||
|
0, 3, 1, 1,
|
||||||
|
true, .Center, false, .Fill)
|
||||||
|
libui.DateTimePickerOnChanged(dtdate, onChanged, l)
|
||||||
|
l = libui.NewLabel("")
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)l,
|
||||||
|
1, 3, 1, 1,
|
||||||
|
true, .Center, false, .Fill)
|
||||||
|
libui.DateTimePickerOnChanged(dttime, onChanged, l)
|
||||||
|
|
||||||
|
b = libui.NewButton("Now")
|
||||||
|
libui.ButtonOnClicked(b, onClicked, cast(rawptr)uintptr(1))
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)b,
|
||||||
|
0, 4, 1, 1,
|
||||||
|
true, .Fill, true, .End)
|
||||||
|
b = libui.NewButton("Unix epoch")
|
||||||
|
libui.ButtonOnClicked(b, onClicked, cast(rawptr)uintptr(0))
|
||||||
|
libui.GridAppend(g, cast(^libui.Control)b,
|
||||||
|
1, 4, 1, 1,
|
||||||
|
true, .Fill, true, .End)
|
||||||
|
|
||||||
|
libui.WindowOnClosing(w, onClosing, nil)
|
||||||
|
libui.ControlShow(cast(^libui.Control)w)
|
||||||
|
libui.Main()
|
||||||
|
}
|
||||||
@@ -0,0 +1,214 @@
|
|||||||
|
package libui_drawtext
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
mainwin: ^libui.Window
|
||||||
|
area: ^libui.Area
|
||||||
|
fontButton: ^libui.FontButton
|
||||||
|
alignment: ^libui.Combobox
|
||||||
|
systemFont: ^libui.Checkbox
|
||||||
|
|
||||||
|
attrstr: ^libui.AttributedString
|
||||||
|
|
||||||
|
appendWithAttribute :: proc(what: cstring, attr: ^libui.Attribute, attr2: ^libui.Attribute) {
|
||||||
|
start := libui.AttributedStringLen(attrstr^)
|
||||||
|
end := start + len(what)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, what)
|
||||||
|
libui.AttributedStringSetAttribute(attrstr, attr, start, end)
|
||||||
|
if attr2 != nil {
|
||||||
|
libui.AttributedStringSetAttribute(attrstr, attr2, start, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
makeAttributedString :: proc() {
|
||||||
|
attrstr = libui.NewAttributedString("Drawing strings with libui is done with the uiAttributedString and uiDrawTextLayout objects.\n" + "uiAttributedString lets you have a variety of attributes: ")
|
||||||
|
|
||||||
|
attr := libui.NewFamilyAttribute("Courier New")
|
||||||
|
appendWithAttribute("font family", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
attr = libui.NewSizeAttribute(18)
|
||||||
|
appendWithAttribute("font size", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
attr = libui.NewWeightAttribute(.Bold)
|
||||||
|
appendWithAttribute("font weight", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
attr = libui.NewItalicAttribute(.Italic)
|
||||||
|
appendWithAttribute("font italicness", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
attr = libui.NewStretchAttribute(.Condensed)
|
||||||
|
appendWithAttribute("font stretch", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
attr = libui.NewColorAttribute(0.75, 0.25, 0.5, 0.75)
|
||||||
|
appendWithAttribute("text color", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
attr = libui.NewBackgroundAttribute(0.5, 0.5, 0.25, 0.5)
|
||||||
|
appendWithAttribute("text background color", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
|
||||||
|
attr = libui.NewUnderlineAttribute(.Single)
|
||||||
|
appendWithAttribute("underline style", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ", ")
|
||||||
|
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, "and ")
|
||||||
|
attr = libui.NewUnderlineAttribute(.Double)
|
||||||
|
attr2 := libui.NewUnderlineColorAttribute(.Custom, 1.0, 0.0, 0.5, 1.0)
|
||||||
|
appendWithAttribute("underline color", attr, attr2)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ". ")
|
||||||
|
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, "Furthermore, there are attributes allowing for ")
|
||||||
|
attr = libui.NewUnderlineAttribute(.Suggestion)
|
||||||
|
attr2 = libui.NewUnderlineColorAttribute(.Spelling, 0, 0, 0, 0)
|
||||||
|
appendWithAttribute("special underlines for indicating spelling errors", attr, attr2)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, " (and other types of errors) ")
|
||||||
|
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, "and control over OpenType features such as ligatures (for instance, ")
|
||||||
|
otf := libui.NewOpenTypeFeatures()
|
||||||
|
libui.OpenTypeFeaturesAdd(otf, 'l', 'i', 'g', 'a', 0)
|
||||||
|
attr = libui.NewFeaturesAttribute(otf)
|
||||||
|
appendWithAttribute("afford", attr, nil)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, " vs. ")
|
||||||
|
libui.OpenTypeFeaturesAdd(otf, 'l', 'i', 'g', 'a', 1)
|
||||||
|
attr = libui.NewFeaturesAttribute(otf)
|
||||||
|
appendWithAttribute("afford", attr, nil)
|
||||||
|
libui.FreeOpenTypeFeatures(otf)
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, ").\n")
|
||||||
|
|
||||||
|
libui.AttributedStringAppendUnattributed(attrstr, "Use the controls opposite to the text to control properties of the text.")
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerDraw :: proc(a: ^libui.AreaHandler, area: ^libui.Area, p: ^libui.AreaDrawParams) {
|
||||||
|
defaultFont: libui.FontDescriptor
|
||||||
|
params: libui.DrawTextLayoutParams
|
||||||
|
useSystemFont := libui.CheckboxChecked(systemFont)
|
||||||
|
|
||||||
|
params.String = attrstr
|
||||||
|
|
||||||
|
if useSystemFont {
|
||||||
|
libui.LoadControlFont(&defaultFont)
|
||||||
|
} else {
|
||||||
|
libui.FontButtonFont(fontButton, &defaultFont)
|
||||||
|
}
|
||||||
|
|
||||||
|
params.DefaultFont = &defaultFont
|
||||||
|
params.Width = p.AreaWidth
|
||||||
|
params.Align = cast(libui.DrawTextAlign)libui.ComboboxSelected(alignment)
|
||||||
|
textLayout := libui.DrawNewTextLayout(¶ms)
|
||||||
|
libui.DrawText(p.Context, textLayout, 0, 0)
|
||||||
|
libui.DrawFreeTextLayout(textLayout)
|
||||||
|
|
||||||
|
libui.FreeFontButtonFont(&defaultFont)
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerMouseEvent :: proc(a: ^libui.AreaHandler, area: ^libui.Area, e: ^libui.AreaMouseEvent) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerMouseCrossed :: proc(ah: ^libui.AreaHandler, a: ^libui.Area, left: c.int) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerDragBroken :: proc(ah: ^libui.AreaHandler, a: ^libui.Area) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerKeyEvent :: proc(ah: ^libui.AreaHandler, a: ^libui.Area, e: ^libui.AreaKeyEvent) -> c.int {
|
||||||
|
// reject all keys
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
onFontChanged :: proc "c" (b: ^libui.FontButton, data: rawptr) {
|
||||||
|
libui.AreaQueueRedrawAll(area)
|
||||||
|
}
|
||||||
|
|
||||||
|
onComboboxSelected :: proc "c" (b: ^libui.Combobox, data: rawptr) {
|
||||||
|
libui.AreaQueueRedrawAll(area)
|
||||||
|
}
|
||||||
|
|
||||||
|
onCheckboxToggled :: proc "c" (b: ^libui.Checkbox, data: rawptr) {
|
||||||
|
libui.AreaQueueRedrawAll(area)
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.ControlDestroy(cast(^libui.Control)mainwin)
|
||||||
|
libui.Quit()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldQuit :: proc "c" (data: rawptr) -> b32 {
|
||||||
|
libui.ControlDestroy(cast(^libui.Control)mainwin)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
handler: libui.AreaHandler
|
||||||
|
o: libui.InitOptions
|
||||||
|
|
||||||
|
handler.Draw = handlerDraw
|
||||||
|
handler.MouseEvent = handlerMouseEvent
|
||||||
|
handler.MouseCrossed = handlerMouseCrossed
|
||||||
|
handler.DragBroken = handlerDragBroken
|
||||||
|
handler.KeyEvent = handlerKeyEvent
|
||||||
|
|
||||||
|
err := libui.Init(&o)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintln("error initializing ui: %s", err)
|
||||||
|
libui.FreeInitError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
libui.OnShouldQuit(shouldQuit, nil)
|
||||||
|
|
||||||
|
makeAttributedString()
|
||||||
|
|
||||||
|
mainwin = libui.NewWindow("libui Text-Drawing Example", 640, 480, true)
|
||||||
|
libui.WindowSetMargined(mainwin, true)
|
||||||
|
libui.WindowOnClosing(mainwin, onClosing, nil)
|
||||||
|
|
||||||
|
hbox := libui.NewHorizontalBox()
|
||||||
|
libui.BoxSetPadded(hbox, true)
|
||||||
|
libui.WindowSetChild(mainwin, cast(^libui.Control)hbox)
|
||||||
|
|
||||||
|
vbox := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)vbox, false)
|
||||||
|
|
||||||
|
fontButton = libui.NewFontButton()
|
||||||
|
libui.FontButtonOnChanged(fontButton, onFontChanged, nil)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)fontButton, false)
|
||||||
|
|
||||||
|
form := libui.NewForm()
|
||||||
|
libui.FormSetPadded(form, true)
|
||||||
|
// on OS X if this is set to 1 then the window can't resize does the form not have the concept of stretchy trailing space?
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)form, false)
|
||||||
|
|
||||||
|
alignment = libui.NewCombobox()
|
||||||
|
// note that the items match with the values of the uiDrawTextAlign values
|
||||||
|
libui.ComboboxAppend(alignment, "Left")
|
||||||
|
libui.ComboboxAppend(alignment, "Center")
|
||||||
|
libui.ComboboxAppend(alignment, "Right")
|
||||||
|
libui.ComboboxSetSelected(alignment, 0) // start with left alignment
|
||||||
|
libui.ComboboxOnSelected(alignment, onComboboxSelected, nil)
|
||||||
|
libui.FormAppend(form, "Alignment", cast(^libui.Control)alignment, false)
|
||||||
|
|
||||||
|
systemFont = libui.NewCheckbox("")
|
||||||
|
libui.CheckboxOnToggled(systemFont, onCheckboxToggled, nil)
|
||||||
|
libui.FormAppend(form, "System Font", cast(^libui.Control)systemFont, false)
|
||||||
|
|
||||||
|
area = libui.NewArea(&handler)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)area, true)
|
||||||
|
|
||||||
|
libui.ControlShow(cast(^libui.Control)mainwin)
|
||||||
|
libui.Main()
|
||||||
|
libui.FreeAttributedString(attrstr)
|
||||||
|
libui.Uninit()
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package libui_hello_world
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
import libui "../../"
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.Quit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
o: libui.InitOptions
|
||||||
|
|
||||||
|
err := libui.Init(&o)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintln("Error initializing libui-ng: %s", err)
|
||||||
|
libui.FreeInitError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new window
|
||||||
|
w := libui.NewWindow("Hello World!", 300, 30, false)
|
||||||
|
libui.WindowOnClosing(w, onClosing, nil)
|
||||||
|
|
||||||
|
l := libui.NewLabel("Hello, World!")
|
||||||
|
libui.WindowSetChild(w, cast(^libui.Control)l)
|
||||||
|
|
||||||
|
libui.ControlShow(cast(^libui.Control)w)
|
||||||
|
libui.Main()
|
||||||
|
libui.Uninit()
|
||||||
|
}
|
||||||
@@ -0,0 +1,297 @@
|
|||||||
|
package libui_histogram
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
import "core:math/rand"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
mainwin: ^libui.Window
|
||||||
|
histogram: ^libui.Area
|
||||||
|
handler: libui.AreaHandler
|
||||||
|
datapoints: [10]^libui.Spinbox
|
||||||
|
colorButton: ^libui.ColorButton
|
||||||
|
currentPoint: c.int = -1
|
||||||
|
|
||||||
|
// some metrics
|
||||||
|
xoffLeft :: 20 /* histogram margins */
|
||||||
|
yoffTop :: 20
|
||||||
|
xoffRight :: 20
|
||||||
|
yoffBottom :: 20
|
||||||
|
pointRadius :: 5
|
||||||
|
|
||||||
|
// and some colors
|
||||||
|
// names and values from https://msdn.microsoft.com/en-us/library/windows/desktop/dd370907%28v=vs.85%29.aspx
|
||||||
|
colorWhite :: 0xFFFFFF
|
||||||
|
colorBlack :: 0x000000
|
||||||
|
colorDodgerBlue :: 0x1E90FF
|
||||||
|
|
||||||
|
// helper to quickly set a brush color
|
||||||
|
setSolidBrush :: proc(brush: ^libui.DrawBrush, color: c.uint32_t, alpha: c.double) {
|
||||||
|
component: c.uint8_t
|
||||||
|
|
||||||
|
brush.Type = .Solid
|
||||||
|
component = cast(c.uint8_t)((color >> 16) & 0xFF)
|
||||||
|
brush.R = (cast(c.double)component) / 255
|
||||||
|
component = cast(c.uint8_t)((color >> 8) & 0xFF)
|
||||||
|
brush.G = (cast(c.double)component) / 255
|
||||||
|
component = cast(c.uint8_t)(color & 0xFF)
|
||||||
|
brush.B = (cast(c.double)component) / 255
|
||||||
|
brush.A = alpha
|
||||||
|
}
|
||||||
|
|
||||||
|
pointLocations :: proc(width: c.double, height: c.double, xs: [^]c.double, ys: [^]c.double) {
|
||||||
|
xincr: c.double
|
||||||
|
yincr: c.double
|
||||||
|
n: c.int
|
||||||
|
|
||||||
|
xincr = width / 9 // 10 - 1 to make the last point be at the end
|
||||||
|
yincr = height / 100
|
||||||
|
|
||||||
|
for i in 0..<10 {
|
||||||
|
// get the value of the point
|
||||||
|
n = libui.SpinboxValue(datapoints[i])
|
||||||
|
// because y=0 is the top but n=0 is the bottom, we need to flip
|
||||||
|
n = 100 - n
|
||||||
|
xs[i] = xincr * f64(i)
|
||||||
|
ys[i] = yincr * f64(n)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructGraph :: proc(width: c.double, height: c.double, extend: bool) -> ^libui.DrawPath {
|
||||||
|
xs: [10]c.double
|
||||||
|
ys: [10]c.double
|
||||||
|
|
||||||
|
pointLocations(width, height, raw_data(&xs), raw_data(&ys))
|
||||||
|
|
||||||
|
path := libui.DrawNewPath(.Winding)
|
||||||
|
|
||||||
|
libui.DrawPathNewFigure(path, xs[0], ys[0])
|
||||||
|
for i in 1..<10 {
|
||||||
|
libui.DrawPathLineTo(path, xs[i], ys[i])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (extend) {
|
||||||
|
libui.DrawPathLineTo(path, width, height)
|
||||||
|
libui.DrawPathLineTo(path, 0, height)
|
||||||
|
libui.DrawPathCloseFigure(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
libui.DrawPathEnd(path)
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
|
||||||
|
graphSize :: proc(clientWidth: c.double, clientHeight: c.double, graphWidth: ^c.double, graphHeight: ^c.double) {
|
||||||
|
graphWidth^ = clientWidth - xoffLeft - xoffRight
|
||||||
|
graphHeight^ = clientHeight - yoffTop - yoffBottom
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerDraw :: proc(a: ^libui.AreaHandler, area: ^libui.Area, p: ^libui.AreaDrawParams) {
|
||||||
|
brush: libui.DrawBrush
|
||||||
|
// initialize sp to 0 to avoid passing garbage to uiDrawStroke()
|
||||||
|
// for example, we don't use dashing
|
||||||
|
sp: libui.DrawStrokeParams
|
||||||
|
m: libui.DrawMatrix
|
||||||
|
graphWidth: c.double
|
||||||
|
graphHeight: c.double
|
||||||
|
graphR: c.double
|
||||||
|
graphG: c.double
|
||||||
|
graphB: c.double
|
||||||
|
graphA: c.double
|
||||||
|
|
||||||
|
// fill the area with white
|
||||||
|
setSolidBrush(&brush, colorWhite, 1.0)
|
||||||
|
path := libui.DrawNewPath(.Winding)
|
||||||
|
libui.DrawPathAddRectangle(path, 0, 0, p.AreaWidth, p.AreaHeight)
|
||||||
|
libui.DrawPathEnd(path)
|
||||||
|
libui.DrawFill(p.Context, path, &brush)
|
||||||
|
libui.DrawFreePath(path)
|
||||||
|
|
||||||
|
// figure out dimensions
|
||||||
|
graphSize(p.AreaWidth, p.AreaHeight, &graphWidth, &graphHeight)
|
||||||
|
|
||||||
|
// make a stroke for both the axes and the histogram line
|
||||||
|
sp.Cap = .Flat
|
||||||
|
sp.Join = .Miter
|
||||||
|
sp.Thickness = 2
|
||||||
|
sp.MiterLimit = libui.DrawDefaultMiterLimit
|
||||||
|
|
||||||
|
// draw the axes
|
||||||
|
setSolidBrush(&brush, colorBlack, 1.0)
|
||||||
|
path = libui.DrawNewPath(.Winding)
|
||||||
|
libui.DrawPathNewFigure(path,
|
||||||
|
xoffLeft, yoffTop)
|
||||||
|
libui.DrawPathLineTo(path,
|
||||||
|
xoffLeft, yoffTop + graphHeight)
|
||||||
|
libui.DrawPathLineTo(path,
|
||||||
|
xoffLeft + graphWidth, yoffTop + graphHeight)
|
||||||
|
libui.DrawPathEnd(path)
|
||||||
|
libui.DrawStroke(p.Context, path, &brush, &sp)
|
||||||
|
libui.DrawFreePath(path)
|
||||||
|
|
||||||
|
// now transform the coordinate space so (0, 0) is the top-left corner of the graph
|
||||||
|
libui.DrawMatrixSetIdentity(&m)
|
||||||
|
libui.DrawMatrixTranslate(&m, xoffLeft, yoffTop)
|
||||||
|
libui.DrawTransform(p.Context, &m)
|
||||||
|
|
||||||
|
// now get the color for the graph itself and set up the brush
|
||||||
|
libui.ColorButtonColor(colorButton, &graphR, &graphG, &graphB, &graphA)
|
||||||
|
brush.Type = .Solid
|
||||||
|
brush.R = graphR
|
||||||
|
brush.G = graphG
|
||||||
|
brush.B = graphB
|
||||||
|
// we set brush.A below to different values for the fill and stroke
|
||||||
|
|
||||||
|
// now create the fill for the graph below the graph line
|
||||||
|
path = constructGraph(graphWidth, graphHeight, true)
|
||||||
|
brush.A = graphA / 2
|
||||||
|
libui.DrawFill(p.Context, path, &brush)
|
||||||
|
libui.DrawFreePath(path)
|
||||||
|
|
||||||
|
// now draw the histogram line
|
||||||
|
path = constructGraph(graphWidth, graphHeight, false)
|
||||||
|
brush.A = graphA
|
||||||
|
libui.DrawStroke(p.Context, path, &brush, &sp)
|
||||||
|
libui.DrawFreePath(path)
|
||||||
|
|
||||||
|
// now draw the point being hovered over
|
||||||
|
if currentPoint != -1 {
|
||||||
|
xs: [10]c.double
|
||||||
|
ys: [10]c.double
|
||||||
|
|
||||||
|
pointLocations(graphWidth, graphHeight, raw_data(&xs), raw_data(&ys))
|
||||||
|
path = libui.DrawNewPath(.Winding)
|
||||||
|
libui.DrawPathNewFigureWithArc(path,
|
||||||
|
xs[currentPoint], ys[currentPoint],
|
||||||
|
pointRadius,
|
||||||
|
0, 6.23,
|
||||||
|
0)
|
||||||
|
libui.DrawPathEnd(path)
|
||||||
|
// use the same brush as for the histogram lines
|
||||||
|
libui.DrawFill(p.Context, path, &brush)
|
||||||
|
libui.DrawFreePath(path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inPoint :: proc(x: c.double, y: c.double, xtest: c.double, ytest: c.double) -> b32 {
|
||||||
|
x := x
|
||||||
|
y := y
|
||||||
|
x -= xoffLeft
|
||||||
|
y -= yoffTop
|
||||||
|
return (x >= xtest - pointRadius) &&
|
||||||
|
(x <= xtest + pointRadius) &&
|
||||||
|
(y >= ytest - pointRadius) &&
|
||||||
|
(y <= ytest + pointRadius)
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerMouseEvent :: proc(a: ^libui.AreaHandler, area: ^libui.Area, e: ^libui.AreaMouseEvent) {
|
||||||
|
graphWidth: c.double
|
||||||
|
graphHeight: c.double
|
||||||
|
i: c.int
|
||||||
|
xs: [10]c.double
|
||||||
|
ys: [10]c.double
|
||||||
|
|
||||||
|
graphSize(e.AreaWidth, e.AreaHeight, &graphWidth, &graphHeight)
|
||||||
|
pointLocations(graphWidth, graphHeight, raw_data(&xs), raw_data(&ys))
|
||||||
|
|
||||||
|
for i in 0..<10 {
|
||||||
|
if (inPoint(e.X, e.Y, xs[i], ys[i])) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if i == 10 { // not in a point
|
||||||
|
i = -1
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPoint = i
|
||||||
|
libui.AreaQueueRedrawAll(histogram)
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerMouseCrossed :: proc(ah: ^libui.AreaHandler, a: ^libui.Area, left: c.int) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerDragBroken :: proc(ah: ^libui.AreaHandler, a: ^libui.Area) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
handlerKeyEvent :: proc(ah: ^libui.AreaHandler, a: ^libui.Area, e: ^libui.AreaKeyEvent) -> c.int {
|
||||||
|
// reject all keys
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
onDatapointChanged :: proc "c" (s: ^libui.Spinbox, data: rawptr) {
|
||||||
|
libui.AreaQueueRedrawAll(histogram)
|
||||||
|
}
|
||||||
|
|
||||||
|
onColorChanged :: proc "c" (b: ^libui.ColorButton, data: rawptr) {
|
||||||
|
libui.AreaQueueRedrawAll(histogram)
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.ControlDestroy(cast(^libui.Control)mainwin)
|
||||||
|
libui.Quit()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldQuit :: proc "c" (data: rawptr) -> b32 {
|
||||||
|
libui.ControlDestroy(cast(^libui.Control)mainwin)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
o: libui.InitOptions
|
||||||
|
brush: libui.DrawBrush
|
||||||
|
|
||||||
|
handler.Draw = handlerDraw
|
||||||
|
handler.MouseEvent = handlerMouseEvent
|
||||||
|
handler.MouseCrossed = handlerMouseCrossed
|
||||||
|
handler.DragBroken = handlerDragBroken
|
||||||
|
handler.KeyEvent = handlerKeyEvent
|
||||||
|
|
||||||
|
err := libui.Init(&o)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintln("error initializing ui: %s", err)
|
||||||
|
libui.FreeInitError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
libui.OnShouldQuit(shouldQuit, nil)
|
||||||
|
|
||||||
|
mainwin = libui.NewWindow("libui Histogram Example", 640, 480, true)
|
||||||
|
libui.WindowSetMargined(mainwin, true)
|
||||||
|
libui.WindowOnClosing(mainwin, onClosing, nil)
|
||||||
|
|
||||||
|
hbox := libui.NewHorizontalBox()
|
||||||
|
libui.BoxSetPadded(hbox, true)
|
||||||
|
libui.WindowSetChild(mainwin, cast(^libui.Control)hbox)
|
||||||
|
|
||||||
|
vbox := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(vbox, true)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)vbox, false)
|
||||||
|
|
||||||
|
for i in 0..<10 {
|
||||||
|
rng := rand.int_max(101)
|
||||||
|
datapoints[i] = libui.NewSpinbox(0, 100)
|
||||||
|
libui.SpinboxSetValue(datapoints[i], auto_cast rng)
|
||||||
|
libui.SpinboxOnChanged(datapoints[i], onDatapointChanged, nil)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)datapoints[i], false)
|
||||||
|
}
|
||||||
|
|
||||||
|
colorButton = libui.NewColorButton()
|
||||||
|
setSolidBrush(&brush, colorDodgerBlue, 1.0)
|
||||||
|
libui.ColorButtonSetColor(colorButton,
|
||||||
|
brush.R,
|
||||||
|
brush.G,
|
||||||
|
brush.B,
|
||||||
|
brush.A)
|
||||||
|
libui.ColorButtonOnChanged(colorButton, onColorChanged, nil)
|
||||||
|
libui.BoxAppend(vbox, cast(^libui.Control)colorButton, false)
|
||||||
|
|
||||||
|
histogram = libui.NewArea(&handler)
|
||||||
|
libui.BoxAppend(hbox, cast(^libui.Control)histogram, true)
|
||||||
|
|
||||||
|
libui.ControlShow(cast(^libui.Control)mainwin)
|
||||||
|
libui.Main()
|
||||||
|
libui.Uninit()
|
||||||
|
}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package libui_multithread
|
||||||
|
|
||||||
|
import "base:runtime"
|
||||||
|
import "core:c/libc"
|
||||||
|
import "core:thread"
|
||||||
|
import "core:sync"
|
||||||
|
import "core:mem"
|
||||||
|
import "core:time"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
// BUG: The program segfaults on exit. Not sure how to fix it.
|
||||||
|
|
||||||
|
e: ^libui.MultilineEntry
|
||||||
|
cv: sync.Cond
|
||||||
|
m: sync.Mutex
|
||||||
|
timeThread: ^thread.Thread
|
||||||
|
|
||||||
|
sayTime :: proc "c" (data: rawptr) {
|
||||||
|
context = runtime.default_context()
|
||||||
|
s := transmute(cstring)data
|
||||||
|
|
||||||
|
libui.MultilineEntryAppend(e, s)
|
||||||
|
delete(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
threadproc :: proc() {
|
||||||
|
sync.lock(&m)
|
||||||
|
for !sync.cond_wait_with_timeout(&cv, &m, time.Second) {
|
||||||
|
s: cstring
|
||||||
|
|
||||||
|
t := libc.time(nil)
|
||||||
|
base := transmute(cstring)libc.ctime(&t)
|
||||||
|
mem.copy(&s, &base, len(base))
|
||||||
|
libui.QueueMain(sayTime, transmute(rawptr)s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
context = runtime.default_context()
|
||||||
|
sync.cond_broadcast(&cv)
|
||||||
|
thread.join(timeThread)
|
||||||
|
libui.Quit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
saySomething :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
libui.MultilineEntryAppend(e, "Saying something\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
o: libui.InitOptions
|
||||||
|
|
||||||
|
if libui.Init(&o) != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w := libui.NewWindow("Hello", 320, 240, false)
|
||||||
|
libui.WindowSetMargined(w, true)
|
||||||
|
|
||||||
|
b := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(b, true)
|
||||||
|
libui.WindowSetChild(w, cast(^libui.Control)b)
|
||||||
|
|
||||||
|
e = libui.NewMultilineEntry()
|
||||||
|
libui.MultilineEntrySetReadOnly(e, true)
|
||||||
|
|
||||||
|
btn := libui.NewButton("Say Something")
|
||||||
|
libui.ButtonOnClicked(btn, saySomething, nil)
|
||||||
|
libui.BoxAppend(b, cast(^libui.Control)btn, false)
|
||||||
|
|
||||||
|
libui.BoxAppend(b, cast(^libui.Control)e, true)
|
||||||
|
|
||||||
|
timeThread = thread.create_and_start(threadproc)
|
||||||
|
|
||||||
|
libui.WindowOnClosing(w, onClosing, nil)
|
||||||
|
libui.ControlShow(cast(^libui.Control)w)
|
||||||
|
libui.Main()
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package libui_timer
|
||||||
|
|
||||||
|
import "core:c"
|
||||||
|
import "core:c/libc"
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
e: ^libui.MultilineEntry
|
||||||
|
|
||||||
|
sayTime :: proc "c" (data: rawptr) -> c.int {
|
||||||
|
t := libc.time(nil)
|
||||||
|
s := libc.ctime(&t)
|
||||||
|
|
||||||
|
libui.MultilineEntryAppend(e, cast(cstring)s)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.Quit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
saySomething :: proc "c" (b: ^libui.Button, data: rawptr) {
|
||||||
|
libui.MultilineEntryAppend(e, "Saying something\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
o: libui.InitOptions
|
||||||
|
|
||||||
|
if libui.Init(&o) != nil {
|
||||||
|
fmt.println("Failed to initialize libui")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w := libui.NewWindow("Hello", 320, 240, false)
|
||||||
|
libui.WindowSetMargined(w, true)
|
||||||
|
|
||||||
|
b := libui.NewVerticalBox()
|
||||||
|
libui.BoxSetPadded(b, true)
|
||||||
|
libui.WindowSetChild(w, cast(^libui.Control)b)
|
||||||
|
|
||||||
|
e = libui.NewMultilineEntry()
|
||||||
|
libui.MultilineEntrySetReadOnly(e, true)
|
||||||
|
|
||||||
|
btn := libui.NewButton("Say Something")
|
||||||
|
libui.ButtonOnClicked(btn, saySomething, nil)
|
||||||
|
libui.BoxAppend(b, cast(^libui.Control)btn, false)
|
||||||
|
|
||||||
|
libui.BoxAppend(b, cast(^libui.Control)e, true)
|
||||||
|
|
||||||
|
libui.Timer(1000, sayTime, nil)
|
||||||
|
|
||||||
|
libui.WindowOnClosing(w, onClosing, nil)
|
||||||
|
libui.ControlShow(cast(^libui.Control)w)
|
||||||
|
libui.Main()
|
||||||
|
}
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
package libui_window
|
||||||
|
|
||||||
|
import "core:fmt"
|
||||||
|
|
||||||
|
import "../../"
|
||||||
|
|
||||||
|
onClosing :: proc "c" (w: ^libui.Window, data: rawptr) -> b32 {
|
||||||
|
libui.Quit()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
main :: proc() {
|
||||||
|
o: libui.InitOptions
|
||||||
|
|
||||||
|
err := libui.Init(&o)
|
||||||
|
if err != nil {
|
||||||
|
fmt.eprintln("Error initializing libui-ng: %s", err)
|
||||||
|
libui.FreeInitError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new window
|
||||||
|
w := libui.NewWindow("Window Title", 300, 30, false)
|
||||||
|
|
||||||
|
libui.WindowOnClosing(w, onClosing, nil)
|
||||||
|
libui.ControlShow(cast(^libui.Control)w)
|
||||||
|
libui.Main()
|
||||||
|
libui.Uninit()
|
||||||
|
}
|
||||||
Binary file not shown.
+3811
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user