Skip to content

Commit

Permalink
Merge pull request #74 from jopbrown/update-7guis
Browse files Browse the repository at this point in the history
update examples/7GUIs
  • Loading branch information
pwiecz committed Apr 27, 2023
2 parents bbadd89 + aa6f546 commit 0f115a9
Show file tree
Hide file tree
Showing 30 changed files with 1,020 additions and 70 deletions.
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

0 comments on commit 0f115a9

Please sign in to comment.