func main() { lua := lgo.NewLua() lua.RegisterFunctions(map[string]interface{}{ // sys "Sys_argv": func() []string { return os.Args[1:] }, "Sys_program_path": func() string { _, path, _, _ := runtime.Caller(0) return filepath.Dir(path) }, "Sys_home": func() string { user, err := user.Current() if err != nil { return "" } return user.HomeDir }, "Sys_exit": func() { os.Exit(0) }, // path "Path_abs": func(p string) string { abs, _ := filepath.Abs(p) return abs }, "Path_dir": func(p string) string { return filepath.Dir(p) }, "Path_base": func(p string) string { return filepath.Base(p) }, "Path_split": func(p string) (string, string) { return filepath.Split(p) }, "Path_join": func(ps []string) string { res := "" for _, part := range ps { res = filepath.Join(res, part) } return res }, "Path_sep": func() string { return string(os.PathSeparator) }, // time "Time_current_time_in_millisecond": func() int64 { t := time.Now().UnixNano() / 1000000 return t }, "Time_tick": func() (ret string) { ret = fmt.Sprintf("%v", time.Now().Sub(t0)) t0 = time.Now() return }, // os "Os_exists": func(p string) bool { _, err := os.Stat(p) return err == nil }, "Os_mkdir": func(p string) bool { return os.Mkdir(p, 0755) != nil }, "Os_list": func(path string) ([]string, bool) { files, err := ioutil.ReadDir(path) if err != nil { return nil, true } var names []string for _, info := range files { names = append(names, info.Name()) } return names, false }, "Os_isdir": func(path string) bool { info, err := os.Stat(path) if err != nil { return false } return info.IsDir() }, "Os_filemode": func(path string) os.FileMode { info, err := os.Stat(path) if err != nil { return 0 } return info.Mode() }, "Os_createwithmode": func(path string, mode uint32) bool { f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE, os.FileMode(mode)) if err != nil { return true } f.Close() return false }, "Os_move": func(src, dst string) bool { info, err := os.Stat(src) if err != nil { return true } mode := info.Mode() _, err = os.Stat(dst) if err == nil { // dst exists return true } f, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, mode) if err != nil { return true } defer f.Close() content, err := ioutil.ReadFile(src) if err != nil { return true } f.Write(content) return false }, "Os_rename": func(src, dst string) bool { return os.Rename(src, dst) != nil }, // text "Text_escapemarkup": func(s string) string { buf := new(bytes.Buffer) err := xml.EscapeText(buf, []byte(s)) if err != nil { return "" } return string(buf.Bytes()) }, "chr": func(r rune) string { return string(r) }, "Text_is_valid_utf8": func(input []byte) bool { return utf8.Valid(input) }, "Text_guess_type": func(text []byte) string { t := mimemagic.Match("", text) if strings.HasPrefix(t, "text/x-") { return strings.Replace(t, "text/x-", "", -1) } return "" }, // regex "Regex_index": func(pattern string, content []byte) interface{} { re, err := regexp.Compile(pattern) if err != nil { return false } indexes := re.FindAllSubmatchIndex(content, -1) if indexes == nil { return false } // convert byte index to char index byte_index := 0 char_index := 0 var size int for i, index := range indexes { for byte_index != index[0] { _, size = utf8.DecodeRune(content[byte_index:]) byte_index += size char_index += 1 } indexes[i][0] = char_index for byte_index != index[1] { _, size = utf8.DecodeRune(content[byte_index:]) byte_index += size char_index += 1 } indexes[i][1] = char_index } return indexes }, "Regex_find": func(pattern, content string) (ret []string) { re := regexp.MustCompile(pattern) if words := re.FindAllString(content, -1); words != nil { ret = words } return }, }) lua.RegisterFunctions(core.Registry) lua.RegisterFunctions(extra.Registry) _, path, _, _ := runtime.Caller(0) lua.RunString(`package.path = '` + filepath.Dir(path) + `' .. '/?.lua;' .. package.path`) go func() { runtime.LockOSThread() lua.RunString(`require 'main'`) }() <-(make(chan bool)) }
func FromLua(code string) map[string]unsafe.Pointer { lua := lgo.NewLua() bindings := make(map[string]unsafe.Pointer) processActorArgs := func(actor *C.ClutterActor, args map[interface{}]interface{}) unsafe.Pointer { pointer := unsafe.Pointer(actor) var minFilter, magFilter *C.ClutterScalingFilter var scaleX C.gdouble = 1.0 var scaleY C.gdouble = 1.0 var translationX, translationY, translationZ C.gfloat for k, v := range args { switch key := k.(type) { case string: switch key { case "id": bindings[v.(string)] = pointer case "bgcolor", "background_color": C.clutter_actor_set_background_color(actor, NewColorFromString(v.(string))) case "clip_rect": clip := (*C.ClutterRect)(v.(unsafe.Pointer)) C.clutter_actor_set_clip(actor, C.gfloat(clip.origin.x), C.gfloat(clip.origin.y), C.gfloat(clip.size.width), C.gfloat(clip.size.height)) case "content": C.clutter_actor_set_content(actor, (*C.ClutterContent)(v.(unsafe.Pointer))) case "content_gravity": switch v.(string) { case "top-left": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_TOP_LEFT) case "top": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_TOP) case "top-right": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_TOP_RIGHT) case "left": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_LEFT) case "center": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_CENTER) case "right": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_RIGHT) case "bottom-left": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_BOTTOM_LEFT) case "bottom": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_BOTTOM) case "bottom-right": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_BOTTOM_RIGHT) case "resize-fill": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_RESIZE_FILL) case "resize-aspect": C.clutter_actor_set_content_gravity(actor, C.CLUTTER_CONTENT_GRAVITY_RESIZE_ASPECT) default: log.Fatalf("unknown content gravity: %s", v.(string)) } case "content_repeat": switch v.(string) { case "none": C.clutter_actor_set_content_repeat(actor, C.CLUTTER_REPEAT_NONE) case "x", "x-axis": C.clutter_actor_set_content_repeat(actor, C.CLUTTER_REPEAT_X_AXIS) case "y", "y-axis": C.clutter_actor_set_content_repeat(actor, C.CLUTTER_REPEAT_Y_AXIS) case "both": C.clutter_actor_set_content_repeat(actor, C.CLUTTER_REPEAT_BOTH) default: log.Fatalf("unknown content repeat: %s", v.(string)) } case "x", "fixed_x": C.clutter_actor_set_x(actor, C.gfloat(v.(float64))) case "y", "fixed_y": C.clutter_actor_set_y(actor, C.gfloat(v.(float64))) case "height": C.clutter_actor_set_height(actor, C.gfloat(v.(float64))) case "layout", "layout_manager": C.clutter_actor_set_layout_manager(actor, (*C.ClutterLayoutManager)(v.(unsafe.Pointer))) case "mag_filter", "magnification_filter": magFilter = (*C.ClutterScalingFilter)(v.(unsafe.Pointer)) C.clutter_actor_set_content_scaling_filters(actor, *minFilter, *magFilter) case "margin_bottom": C.clutter_actor_set_margin_bottom(actor, C.gfloat(v.(float64))) case "margin_left": C.clutter_actor_set_margin_left(actor, C.gfloat(v.(float64))) case "margin_right": C.clutter_actor_set_margin_right(actor, C.gfloat(v.(float64))) case "margin_top": C.clutter_actor_set_margin_top(actor, C.gfloat(v.(float64))) //TODO min height //TODO min width case "min_filter", "minification_filter": minFilter = (*C.ClutterScalingFilter)(v.(unsafe.Pointer)) C.clutter_actor_set_content_scaling_filters(actor, *minFilter, *magFilter) case "name": C.clutter_actor_set_name(actor, toGStr(v.(string))) //TODO natural height //TODO natural width case "offscreen_redirect": switch v.(string) { case "auto", "automatic-for-opacity": C.clutter_actor_set_offscreen_redirect(actor, C.CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY) case "always": C.clutter_actor_set_offscreen_redirect(actor, C.CLUTTER_OFFSCREEN_REDIRECT_ALWAYS) default: log.Fatalf("unknown offscreen redirect option: %s", v.(string)) } case "opacity": C.clutter_actor_set_opacity(actor, C.guint8(uint8(v.(float64)))) case "pivot_point": point := (*C.ClutterPoint)(v.(unsafe.Pointer)) C.clutter_actor_set_pivot_point(actor, C.gfloat(point.x), C.gfloat(point.y)) case "pivot_point_z": C.clutter_actor_set_pivot_point_z(actor, C.gfloat(v.(float64))) case "position": point := (*C.ClutterPoint)(v.(unsafe.Pointer)) C.clutter_actor_set_position(actor, C.gfloat(point.x), C.gfloat(point.y)) case "reactive": b := C.FALSE if v.(bool) { b = C.TRUE } C.clutter_actor_set_reactive(actor, C.gboolean(b)) case "request_mode": switch v.(string) { case "height", "height_for_width": C.clutter_actor_set_request_mode(actor, C.CLUTTER_REQUEST_HEIGHT_FOR_WIDTH) case "width", "width_for_height": C.clutter_actor_set_request_mode(actor, C.CLUTTER_REQUEST_WIDTH_FOR_HEIGHT) default: log.Fatalf("unknown request mode: %s", v.(string)) } case "rotation_angle_x": C.clutter_actor_set_rotation_angle(actor, C.CLUTTER_X_AXIS, C.gdouble(v.(float64))) case "rotation_angle_y": C.clutter_actor_set_rotation_angle(actor, C.CLUTTER_Y_AXIS, C.gdouble(v.(float64))) case "rotation_angle_z": C.clutter_actor_set_rotation_angle(actor, C.CLUTTER_Z_AXIS, C.gdouble(v.(float64))) case "scale_x": scaleX = C.gdouble(v.(float64)) C.clutter_actor_set_scale(actor, scaleX, scaleY) case "scale_y": scaleY = C.gdouble(v.(float64)) C.clutter_actor_set_scale(actor, scaleX, scaleY) case "scale_z": C.clutter_actor_set_scale_z(actor, C.gdouble(v.(float64))) case "size": size := (*C.ClutterSize)(v.(unsafe.Pointer)) C.clutter_actor_set_size(actor, C.gfloat(size.width), C.gfloat(size.height)) case "text_direction", "text_dir": switch v.(string) { case "default": C.clutter_actor_set_text_direction(actor, C.CLUTTER_TEXT_DIRECTION_DEFAULT) case "left", "left-to-right", "ltr": C.clutter_actor_set_text_direction(actor, C.CLUTTER_TEXT_DIRECTION_LTR) case "right", "right-to-left", "rtl": C.clutter_actor_set_text_direction(actor, C.CLUTTER_TEXT_DIRECTION_RTL) default: log.Fatalf("unknown text direction: %s", v.(string)) } //TODO transform case "translation_x": translationX = C.gfloat(v.(float64)) C.clutter_actor_set_translation(actor, translationX, translationY, translationZ) case "translation_y": translationY = C.gfloat(v.(float64)) C.clutter_actor_set_translation(actor, translationX, translationY, translationZ) case "translation_z": translationZ = C.gfloat(v.(float64)) C.clutter_actor_set_translation(actor, translationX, translationY, translationZ) case "visible": if v.(bool) { C.clutter_actor_show(actor) } else { C.clutter_actor_hide(actor) } case "width": C.clutter_actor_set_width(actor, C.gfloat(v.(float64))) case "x_align": switch v.(string) { case "fill": C.clutter_actor_set_x_align(actor, C.CLUTTER_ACTOR_ALIGN_FILL) case "start": C.clutter_actor_set_x_align(actor, C.CLUTTER_ACTOR_ALIGN_START) case "center": C.clutter_actor_set_x_align(actor, C.CLUTTER_ACTOR_ALIGN_CENTER) case "end": C.clutter_actor_set_x_align(actor, C.CLUTTER_ACTOR_ALIGN_END) default: log.Fatalf("unknown x align: %s", v.(string)) } case "x_expand": b := C.FALSE if v.(bool) { b = C.TRUE } C.clutter_actor_set_x_expand(actor, C.gboolean(b)) case "y_align": switch v.(string) { case "fill": C.clutter_actor_set_y_align(actor, C.CLUTTER_ACTOR_ALIGN_FILL) case "start": C.clutter_actor_set_y_align(actor, C.CLUTTER_ACTOR_ALIGN_START) case "center": C.clutter_actor_set_y_align(actor, C.CLUTTER_ACTOR_ALIGN_CENTER) case "end": C.clutter_actor_set_y_align(actor, C.CLUTTER_ACTOR_ALIGN_END) default: log.Fatalf("unknown y align: %s", v.(string)) } case "y_expand": b := C.FALSE if v.(bool) { b = C.TRUE } C.clutter_actor_set_y_expand(actor, C.gboolean(b)) case "z", "z_position": C.clutter_actor_set_z_position(actor, C.gfloat(v.(float64))) } case float64: switch value := v.(type) { case unsafe.Pointer: //TODO add tests if IsActor(value) { // actor child C.clutter_actor_add_child(actor, (*C.ClutterActor)(value)) } else if IsAction(value) { // action C.clutter_actor_add_action(actor, (*C.ClutterAction)(value)) } else if IsConstraint(value) { // constraint C.clutter_actor_add_constraint(actor, (*C.ClutterConstraint)(value)) } else if IsEffect(value) { // effect C.clutter_actor_add_effect(actor, (*C.ClutterEffect)(value)) } else { log.Fatalf("unknown subelement type") } } } } return pointer } processBoxArgs := func(box *C.ClutterLayoutManager, args map[string]interface{}) { //TODO } lua.RegisterFunctions(map[string]interface{}{ // actors "Actor": func(args map[interface{}]interface{}) unsafe.Pointer { actor := C.clutter_actor_new() return processActorArgs(actor, args) }, "Stage": func(args map[interface{}]interface{}) unsafe.Pointer { window := C.gtk_window_new(C.GTK_WINDOW_TOPLEVEL) embed := C.gtk_clutter_embed_new() C.gtk_container_add((*C.GtkContainer)(unsafe.Pointer(window)), embed) actor := C.gtk_clutter_embed_get_stage((*C.GtkClutterEmbed)(unsafe.Pointer(embed))) C.clutter_actor_show(actor) C.gtk_widget_show_all((*C.GtkWidget)(unsafe.Pointer(window))) pointer := processActorArgs(actor, args) stage := (*C.ClutterStage)(unsafe.Pointer(actor)) for k, v := range args { //TODO other properties switch key := k.(type) { case string: switch key { case "title": C.clutter_stage_set_title(stage, toGStr(v.(string))) } } } return pointer }, "Text": func(args map[interface{}]interface{}) unsafe.Pointer { actor := C.clutter_text_new() pointer := processActorArgs(actor, args) text := (*C.ClutterText)(unsafe.Pointer(actor)) for k, v := range args { //TODO other properties switch key := k.(type) { case string: switch key { case "text": C.clutter_text_set_text(text, toGStr(v.(string))) case "use_markup": b := C.FALSE if v.(bool) { b = C.TRUE } C.clutter_text_set_use_markup(text, C.gboolean(b)) case "markup": C.clutter_text_set_markup(text, toGStr(v.(string))) case "color": C.clutter_text_set_color(text, NewColorFromString(v.(string))) } case float64: } } return pointer }, // data structures "Point": func(args []float64) unsafe.Pointer { var point C.ClutterPoint point.x = C.float(args[0]) point.y = C.float(args[1]) return unsafe.Pointer(&point) }, "Size": func(args []float64) unsafe.Pointer { var size C.ClutterSize size.width = C.float(args[0]) size.height = C.float(args[1]) return unsafe.Pointer(&size) }, "Rect": func(args []float64) unsafe.Pointer { var rect C.ClutterRect var point C.ClutterPoint var size C.ClutterSize point.x = C.float(args[0]) point.y = C.float(args[1]) size.width = C.float(args[2]) size.height = C.float(args[3]) rect.origin = point rect.size = size return unsafe.Pointer(&rect) }, // contents "Image": func(args []string) unsafe.Pointer { //TODO set data image := C.clutter_image_new() return unsafe.Pointer(image) }, // layouts "Box": func(args map[string]interface{}) unsafe.Pointer { box := C.clutter_box_layout_new() processBoxArgs(box, args) return unsafe.Pointer(box) }, "HBox": func(args map[string]interface{}) unsafe.Pointer { box := C.clutter_box_layout_new() C.clutter_box_layout_set_orientation((*C.ClutterBoxLayout)(unsafe.Pointer(box)), C.CLUTTER_ORIENTATION_HORIZONTAL) processBoxArgs(box, args) return unsafe.Pointer(box) }, "VBox": func(args map[string]interface{}) unsafe.Pointer { box := C.clutter_box_layout_new() C.clutter_box_layout_set_orientation((*C.ClutterBoxLayout)(unsafe.Pointer(box)), C.CLUTTER_ORIENTATION_VERTICAL) processBoxArgs(box, args) return unsafe.Pointer(box) }, // effects "Blur": func(args map[string]interface{}) unsafe.Pointer { effect := C.clutter_blur_effect_new() return unsafe.Pointer(effect) }, // constraints "Align": func(args map[string]interface{}) unsafe.Pointer { constraint := C.clutter_align_constraint_new(nil, C.CLUTTER_ALIGN_X_AXIS, 0) align := (*C.ClutterAlignConstraint)(unsafe.Pointer(constraint)) for key, v := range args { switch key { case "source": C.clutter_align_constraint_set_source(align, (*C.ClutterActor)(bindings[v.(string)])) case "axis": switch v.(string) { case "x", "X": C.clutter_align_constraint_set_align_axis(align, C.CLUTTER_ALIGN_X_AXIS) case "y", "Y": C.clutter_align_constraint_set_align_axis(align, C.CLUTTER_ALIGN_Y_AXIS) case "both", "BOTH", "Both": C.clutter_align_constraint_set_align_axis(align, C.CLUTTER_ALIGN_BOTH) } case "factor": C.clutter_align_constraint_set_factor(align, C.gfloat(v.(float64))) } } return unsafe.Pointer(constraint) }, }) lua.RunString(code) return bindings }