Skip to content
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

update examples/7GUIs #74

Merged
merged 1 commit into from
Apr 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions events.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ int go_fltk_event_dx() { return Fl::event_dx(); }
int go_fltk_event_dy() { return Fl::event_dy(); }
int go_fltk_event_key() { return Fl::event_key(); }
int go_fltk_event_is_click() { return Fl::event_is_click(); }
int go_fltk_event_clicks() { return Fl::event_clicks(); }
int go_fltk_event_state() { return Fl::event_state(); }
const char* go_fltk_event_text() { return Fl::event_text(); }
3 changes: 3 additions & 0 deletions events.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ func EventKey() int {
func EventIsClick() bool {
return C.go_fltk_event_is_click() != 0
}
func EventClicks() int {
return int(C.go_fltk_event_clicks())
}
func EventText() string {
return C.GoString(C.go_fltk_event_text())
}
Expand Down
1 change: 1 addition & 0 deletions events.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ extern "C" {
extern int go_fltk_event_dy();
extern int go_fltk_event_key();
extern int go_fltk_event_is_click();
extern int go_fltk_event_clicks();
extern int go_fltk_event_state();
extern const char* go_fltk_event_text();

Expand Down
39 changes: 39 additions & 0 deletions examples/7GUIs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 7GUIs examples

These are examples of implementing [7GUIs](https://eugenkiss.github.io/7guis/).

The implementation heavily references:
1. [7guis-fltk-rs](https://github.com/tdryer/7guis-fltk-rs)
2. [7GUIs Implementation in IUP](https://www.tecgraf.puc-rio.br/iup/en/7gui/7gui.html)

## Counter

![screenshot](counter/screenshot.png)

## Temperature Converter

![screenshot](temperature/screenshot.png)

## Flight Booker

![one way flight](flightbooker/screenshot1.png)
![abnormal](flightbooker/screenshot2.png)
![return flight](flightbooker/screenshot3.png)

## Timer

![screenshot](timer/screenshot.png)

## CRUD

![screenshot](crud/screenshot.png)

## Circle Drawer

![screenshot](circle/screenshot.png)

## Cells

> only implement the `SUM()` formula.

![screenshot](cells/screenshot.png)
256 changes: 256 additions & 0 deletions examples/7GUIs/cells/context.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,256 @@
package main

import (
"errors"
"fmt"
"math"
"regexp"
"strconv"
"strings"
)

var reSumFormula = regexp.MustCompile(`(?i)SUM\(([A-Z]\d+):([A-Z]\d+)\)`)

type Context struct {
Cells [][]*Cell
}

func NewContext(maxRow, maxCol int) *Context {
ctx := &Context{}
ctx.Cells = make([][]*Cell, maxRow)
for row := range ctx.Cells {
ctx.Cells[row] = make([]*Cell, maxCol)
for col := range ctx.Cells[row] {
cell := &Cell{}
cell.Loc.Row = CellRow(row)
cell.Loc.Col = CellCol(col)
cell.Data = &CellDataText{}
ctx.Cells[row][col] = cell
}
}

return ctx
}

func (ctx *Context) FindCell(loc CellLoc) *Cell {
if int(loc.Row) >= len(ctx.Cells) || int(loc.Col) >= len(ctx.Cells[loc.Row]) {
return nil
}
return ctx.Cells[loc.Row][loc.Col]
}

func ParseCellData(value string) CellData {
if strings.HasPrefix(value, "=") {
formula := value[1:]
matches := reSumFormula.FindStringSubmatch(formula)
if matches == nil {
return &CellDataInvalid{Reason: "SUPPORT FORMULA"}
}

strStartLoc := matches[1]
startLoc, err := ParseCellLoc(strStartLoc)
if err != nil {
return &CellDataInvalid{Reason: "INVALID START CELL"}
}

strEndLoc := matches[2]
endLoc, err := ParseCellLoc(strEndLoc)
if err != nil {
return &CellDataInvalid{Reason: "INVALID END CELL"}
}

formulaData := &CellDataFormula{}
formulaData.Formula = formula
formulaData.CalCells = make(map[CellLoc]*Cell)
for row := startLoc.Row; row <= endLoc.Row; row++ {
for col := startLoc.Col; col <= endLoc.Col; col++ {
loc := CellLoc{Row: row, Col: col}
formulaData.CalCells[loc] = ctx.FindCell(loc)
}
}
return formulaData
}

num, err := strconv.ParseFloat(value, 64)
if err == nil {
return &CellDataNumber{Number: num}
}

return &CellDataText{Text: value}
}

func (cell *Cell) Update(value string) {
cellData := ParseCellData(value)
cell.Data = cellData
cell.RawValue = value
}

func (ctx *Context) FindAllChangedCells(cell *Cell) map[CellLoc]*Cell {
changedCells := make(map[CellLoc]*Cell)
changedCells[cell.Loc] = cell

ctx.findAllChangedCells(cell, changedCells)

return changedCells
}

func (ctx *Context) findAllChangedCells(cell *Cell, changedCells map[CellLoc]*Cell) {
for row := range ctx.Cells {
for col := range ctx.Cells[row] {
changedCell := ctx.Cells[row][col]
if changedCell.Data.IsDependOn(cell) {
if _, exist := changedCells[changedCell.Loc]; !exist {
changedCells[changedCell.Loc] = changedCell
ctx.findAllChangedCells(changedCell, changedCells)
} else {
changedCell.Data = &CellDataInvalid{Reason: "RECURSIVE FORMULA"}
}
}
}
}
}

func (ctx *Context) UpdateCellAtLoc(locStr string, value string) {
loc, err := ParseCellLoc(locStr)
if err != nil {
return
}
cell := ctx.FindCell(loc)
if cell == nil {
return
}
cell.Update(value)
}

type Cell struct {
Loc CellLoc
Data CellData
RawValue string
}

type CellRow int

func (row CellRow) String() string {
return strconv.Itoa(int(row))
}

type CellCol int

func (col CellCol) String() string {
return string('A' + byte(col))
}

type CellLoc struct {
Row CellRow
Col CellCol
}

func (loc CellLoc) String() string {
return loc.Col.String() + loc.Row.String()
}

var ZERO_CELL_LOC = CellLoc{0, 0}

func ParseCellLoc(str string) (CellLoc, error) {
loc := ZERO_CELL_LOC

if len(str) < 2 {
return loc, errors.New("invalid cell location: len(str) < 2")
}

str = strings.ToUpper(str)

runeCol := str[0]
if runeCol > 'Z' || runeCol < 'A' {
return ZERO_CELL_LOC, fmt.Errorf("invalid cell column: '%c'", runeCol)
}
loc.Col = CellCol(runeCol - 'A')

strRow := str[1:]
irow, err := strconv.Atoi(strRow)
if err != nil {
return ZERO_CELL_LOC, fmt.Errorf("invalid cell row: '%s'", strRow)
}
loc.Row = CellRow(irow)

return loc, nil
}

type CellData interface {
Eval() float64
Display() string
IsDependOn(cell *Cell) bool
}

type CellDataNumber struct {
Number float64
}

func (data *CellDataNumber) Eval() float64 {
return data.Number
}

func (data *CellDataNumber) Display() string {
return fmt.Sprintf("%f", data.Number)
}

func (data *CellDataNumber) IsDependOn(cell *Cell) bool {
return false
}

type CellDataFormula struct {
Formula string
CalCells map[CellLoc]*Cell
}

func (data *CellDataFormula) Eval() float64 {
sum := 0.0
for _, calCell := range data.CalCells {
if calCell != nil {
sum += calCell.Data.Eval()
}
}
return sum
}

func (data *CellDataFormula) Display() string {
num := data.Eval()
return fmt.Sprintf("%f", num)
}

func (data *CellDataFormula) IsDependOn(cell *Cell) bool {
_, ok := data.CalCells[cell.Loc]
return ok
}

type CellDataInvalid struct {
Reason string
}

func (data *CellDataInvalid) Eval() float64 {
return math.NaN()
}

func (data *CellDataInvalid) Display() string {
return data.Reason
}

func (data *CellDataInvalid) IsDependOn(cell *Cell) bool {
return false
}

type CellDataText struct {
Text string
}

func (data *CellDataText) Eval() float64 {
return 0.0
}

func (data *CellDataText) Display() string {
return data.Text
}

func (data *CellDataText) IsDependOn(cell *Cell) bool {
return false
}
48 changes: 48 additions & 0 deletions examples/7GUIs/cells/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"github.com/pwiecz/go-fltk"
)

const (
WIDGET_HEIGHT = 200
WIDGET_WIDTH = 450
)

const (
MAX_ROW_COUNT = 100 // 0~99
MAX_COL_COUNT = 26 // A~Z
)

var ctx = NewContext(MAX_ROW_COUNT, MAX_COL_COUNT)

func init() {
ctx.UpdateCellAtLoc("B1", "5")
ctx.UpdateCellAtLoc("B2", "1")
ctx.UpdateCellAtLoc("B3", "10.3")
ctx.UpdateCellAtLoc("B4", "22.87")
ctx.UpdateCellAtLoc("B5", "=SUM(B1:B4)")
ctx.UpdateCellAtLoc("C1", "6")
ctx.UpdateCellAtLoc("C2", "7")
ctx.UpdateCellAtLoc("C3", "2")
ctx.UpdateCellAtLoc("C4", "5")
ctx.UpdateCellAtLoc("C5", "=SUM(C1:C4)")
ctx.UpdateCellAtLoc("A5", "Sum")
ctx.UpdateCellAtLoc("D5", "=SUM(B5:C5)")
}

func main() {
fltk.SetScheme("gtk+")

win := fltk.NewWindow(
WIDGET_WIDTH,
WIDGET_HEIGHT)
win.SetLabel("Cells")

p := NewPanel(win, MAX_ROW_COUNT, MAX_COL_COUNT)
p.Bind(ctx)

win.End()
win.Show()
fltk.Run()
}
Loading