func finishNewTable(b *tablebase, ty reflect.Type) Table { id := C.newTable() t := &table{ scroller: newScroller(id, true), // border on Table tablebase: b, selected: newEvent(), } t.fpreferredSize = t.xpreferredSize // also sets the delegate C.tableMakeDataSource(t.id, unsafe.Pointer(t)) for i := 0; i < ty.NumField(); i++ { colname := ty.Field(i).Tag.Get("uicolumn") if colname == "" { colname = ty.Field(i).Name } cname := C.CString(colname) coltype := C.colTypeText editable := false switch { case ty.Field(i).Type == reflect.TypeOf((*image.RGBA)(nil)): coltype = C.colTypeImage case ty.Field(i).Type.Kind() == reflect.Bool: coltype = C.colTypeCheckbox editable = true } C.tableAppendColumn(t.id, C.intptr_t(i), cname, C.int(coltype), toBOOL(editable)) C.free(unsafe.Pointer(cname)) // free now (not deferred) to conserve memory } return t }
//export goTableDataSource_getValue func goTableDataSource_getValue(data unsafe.Pointer, row C.intptr_t, col C.intptr_t, outtype *C.int) unsafe.Pointer { t := (*table)(data) t.RLock() defer t.RUnlock() d := reflect.Indirect(reflect.ValueOf(t.data)) datum := d.Index(int(row)).Field(int(col)) switch { case datum.Type() == reflect.TypeOf((*image.RGBA)(nil)): *outtype = C.colTypeImage d := datum.Interface().(*image.RGBA) img := C.toTableImage(unsafe.Pointer(pixelData(d)), C.intptr_t(d.Rect.Dx()), C.intptr_t(d.Rect.Dy()), C.intptr_t(d.Stride)) return unsafe.Pointer(img) case datum.Kind() == reflect.Bool: *outtype = C.colTypeCheckbox if datum.Bool() == true { // return a non-nil pointer // outtype isn't Go-side so it'll work return unsafe.Pointer(outtype) } return nil default: s := fmt.Sprintf("%v", datum) return unsafe.Pointer(C.CString(s)) } }
//export tableGetCell func tableGetCell(data unsafe.Pointer, tnm *C.tableNM) C.LRESULT { t := (*table)(data) t.RLock() defer t.RUnlock() d := reflect.Indirect(reflect.ValueOf(t.data)) datum := d.Index(int(tnm.row)).Field(int(tnm.column)) switch { case datum.Type() == reflect.TypeOf((*image.RGBA)(nil)): i := datum.Interface().(*image.RGBA) hbitmap := C.toBitmap(unsafe.Pointer(i), C.intptr_t(i.Rect.Dx()), C.intptr_t(i.Rect.Dy())) bitmap := C.uintptr_t(uintptr(unsafe.Pointer(hbitmap))) t.freeLock.Lock() t.free[bitmap] = true // bitmap freed with C.freeBitmap() t.freeLock.Unlock() return C.LRESULT(bitmap) case datum.Kind() == reflect.Bool: if datum.Bool() == true { return C.TRUE } return C.FALSE default: s := fmt.Sprintf("%v", datum) text := C.uintptr_t(uintptr(unsafe.Pointer(toUTF16(s)))) t.freeLock.Lock() t.free[text] = false // text freed with C.free() t.freeLock.Unlock() return C.LRESULT(text) } }
func (l *label) commitResize(c *allocation, d *sizing) { if !l.standalone && c.neighbor != nil { c.neighbor.getAuxResizeInfo(d) if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline // in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE! // otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong origsize := C.controlPreferredSize(l._id) c.height = int(origsize.height) newrect := C.struct_xrect{ x: C.intptr_t(c.x), y: C.intptr_t(c.y), width: C.intptr_t(c.width), height: C.intptr_t(c.height), } ourAlign := C.alignmentInfo(l._id, newrect) // we need to find the exact Y positions of the baselines // fortunately, this is easy now that (x,y) is the bottom-left corner thisbasey := ourAlign.rect.y + ourAlign.baseline neighborbasey := d.neighborAlign.rect.y + d.neighborAlign.baseline // now the amount we have to move the label down by is easy to find yoff := neighborbasey - thisbasey // and we just add that c.y += int(yoff) } // in the other case, the most correct thing would be for Label to be aligned to the alignment rect, but I can't get this working, and it looks fine as it is anyway } basecommitResize(l, c, d) }
func (s *sysData) setRect(x int, y int, width int, height int, winheight int) error { // winheight - y because (0,0) is the bottom-left corner of the window and not the top-left corner // (winheight - y) - height because (x, y) is the bottom-left corner of the control and not the top-left C.setRect(s.id, C.intptr_t(x), C.intptr_t((winheight-y)-height), C.intptr_t(width), C.intptr_t(height)) return nil }
func (s *sysData) setAreaSize(width int, height int) { ret := make(chan struct{}) defer close(ret) uitask <- func() { C.setAreaSize(s.id, C.intptr_t(width), C.intptr_t(height)) ret <- struct{}{} } <-ret }
func (s *sysData) setWindowSize(width int, height int) error { ret := make(chan struct{}) defer close(ret) uitask <- func() { C.windowSetContentSize(s.id, C.intptr_t(width), C.intptr_t(height)) ret <- struct{}{} } <-ret return nil }
func (a *area) Repaint(r image.Rectangle) { var s C.struct_xrect r = image.Rect(0, 0, a.width, a.height).Intersect(r) if r.Empty() { return } s.x = C.intptr_t(r.Min.X) s.y = C.intptr_t(r.Min.Y) s.width = C.intptr_t(r.Dx()) s.height = C.intptr_t(r.Dy()) C.areaRepaint(a.id, s) }
//export containerResized func containerResized(data unsafe.Pointer) { c := (*container)(data) d := beginResize() // TODO make this a parameter b := C.containerBounds(c.id) if c.margined { b.x += C.intptr_t(macXMargin) b.y += C.intptr_t(macYMargin) b.width -= C.intptr_t(macXMargin) * 2 b.height -= C.intptr_t(macYMargin) * 2 } c.resize(int(b.x), int(b.y), int(b.width), int(b.height), d) }
func newWindow(title string, width int, height int, control Control) *window { id := C.newWindow(C.intptr_t(width), C.intptr_t(height)) ctitle := C.CString(title) defer C.free(unsafe.Pointer(ctitle)) C.windowSetTitle(id, ctitle) w := &window{ id: id, closing: newEvent(), container: newContainer(control), } C.windowSetDelegate(w.id, unsafe.Pointer(w)) C.windowSetContentView(w.id, w.container.id) return w }
func (s *sysData) commitResize(c *allocation, d *sysSizeData) { if s.ctype == c_label && !s.alternate && c.neighbor != nil { c.neighbor.getAuxResizeInfo(d) if d.neighborAlign.baseline != 0 { // no adjustment needed if the given control has no baseline // in order for the baseline value to be correct, the label MUST BE AT THE HEIGHT THAT OS X WANTS IT TO BE! // otherwise, the baseline calculation will be relative to the bottom of the control, and everything will be wrong origsize := C.controlPrefSize(s.id) c.height = int(origsize.height) newrect := C.struct_xrect{ x: C.intptr_t(c.x), y: C.intptr_t(c.y), width: C.intptr_t(c.width), height: C.intptr_t(c.height), } ourAlign := C.alignmentInfo(s.id, newrect) // we need to find the exact Y positions of the baselines // fortunately, this is easy now that (x,y) is the bottom-left corner thisbasey := ourAlign.alignmentRect.y + ourAlign.baseline neighborbasey := d.neighborAlign.alignmentRect.y + d.neighborAlign.baseline // now the amount we have to move the label down by is easy to find yoff := neighborbasey - thisbasey // and we just add that c.y += int(yoff) } // TODO if there's no baseline, the alignment should be to the top /of the alignment rect/, not the frame } C.setRect(s.id, C.intptr_t(c.x), C.intptr_t(c.y), C.intptr_t(c.width), C.intptr_t(c.height)) }
//export doPaint func doPaint(xrect *C.RECT, hscroll C.int, vscroll C.int, data unsafe.Pointer, dx *C.intptr_t, dy *C.intptr_t) unsafe.Pointer { a := (*area)(data) // both Windows RECT and Go image.Rect are point..point, so the following is correct cliprect := image.Rect(int(xrect.left), int(xrect.top), int(xrect.right), int(xrect.bottom)) cliprect = cliprect.Add(image.Pt(int(hscroll), int(vscroll))) // adjust by scroll position // make sure the cliprect doesn't fall outside the size of the Area cliprect = cliprect.Intersect(image.Rect(0, 0, a.width, a.height)) if !cliprect.Empty() { // we have an update rect i := a.handler.Paint(cliprect) *dx = C.intptr_t(i.Rect.Dx()) *dy = C.intptr_t(i.Rect.Dy()) return unsafe.Pointer(i) } return nil }
//export areaView_drawRect func areaView_drawRect(self C.id, rect C.struct_xrect) { s := getSysData(self) // no need to clear the clip rect; the NSScrollView does that for us (see the setDrawsBackground: call in objc_darwin.m) // rectangles in Cocoa are origin/size, not point0/point1; if we don't watch for this, weird things will happen when scrolling cliprect := image.Rect(int(rect.x), int(rect.y), int(rect.x+rect.width), int(rect.y+rect.height)) max := C.frame(self) cliprect = image.Rect(0, 0, int(max.width), int(max.height)).Intersect(cliprect) if cliprect.Empty() { // no intersection; nothing to paint return } i := s.handler.Paint(cliprect) C.drawImage( unsafe.Pointer(pixelData(i)), C.intptr_t(i.Rect.Dx()), C.intptr_t(i.Rect.Dy()), C.intptr_t(i.Stride), C.intptr_t(cliprect.Min.X), C.intptr_t(cliprect.Min.Y)) }
//export goTableDataSource_getRowCount func goTableDataSource_getRowCount(data unsafe.Pointer) C.intptr_t { t := (*table)(data) t.RLock() defer t.RUnlock() d := reflect.Indirect(reflect.ValueOf(t.data)) return C.intptr_t(d.Len()) }
func newWindow(title string, width int, height int, control Control) *window { id := C.newWindow(C.intptr_t(width), C.intptr_t(height)) ctitle := C.CString(title) defer C.free(unsafe.Pointer(ctitle)) C.windowSetTitle(id, ctitle) w := &window{ id: id, closing: newEvent(), child: control, } C.windowSetDelegate(w.id, unsafe.Pointer(w)) w.container = newContainer(w.child.resize) w.child.setParent(w.container.parent()) C.windowSetContentView(w.id, w.container.id) // trigger an initial resize return w }
//export areaView_drawRect func areaView_drawRect(self C.id, rect C.struct_xrect, data unsafe.Pointer) { a := (*area)(data) // no need to clear the clip rect; the NSScrollView does that for us (see the setDrawsBackground: call in objc_darwin.m) // rectangles in Cocoa are origin/size, not point0/point1; if we don't watch for this, weird things will happen when scrolling cliprect := image.Rect(int(rect.x), int(rect.y), int(rect.x+rect.width), int(rect.y+rect.height)) cliprect = image.Rect(0, 0, int(a.width), int(a.height)).Intersect(cliprect) if cliprect.Empty() { // no intersection; nothing to paint return } i := a.handler.Paint(cliprect) success := C.drawImage( unsafe.Pointer(pixelData(i)), C.intptr_t(i.Rect.Dx()), C.intptr_t(i.Rect.Dy()), C.intptr_t(i.Stride), C.intptr_t(cliprect.Min.X), C.intptr_t(cliprect.Min.Y)) if success == C.NO { panic("error drawing into Area (exactly what is unknown)") } }
func (s *sysData) setProgress(percent int) { ret := make(chan struct{}) defer close(ret) uitask <- func() { C.setProgress(s.id, C.intptr_t(percent)) ret <- struct{}{} } <-ret }
func (t *table) Unlock() { t.unlock() // there's a possibility that user actions can happen at this point, before the view is updated // alas, this is something we have to deal with, because Unlock() can be called from any thread go func() { Do(func() { t.RLock() defer t.RUnlock() C.gotableSetRowCount(t.hwnd, C.intptr_t(reflect.Indirect(reflect.ValueOf(t.data)).Len())) }) }() }
//export hookGoValueReadField func hookGoValueReadField(enginep, foldp unsafe.Pointer, reflectIndex, getIndex, setIndex C.int, resultdv *C.DataValue) { fold := ensureEngine(enginep, foldp) var field reflect.Value if getIndex >= 0 { field = reflect.ValueOf(fold.gvalue).Method(int(getIndex)).Call(nil)[0] } else { field = deref(reflect.ValueOf(fold.gvalue)).Field(int(reflectIndex)) } field = deref(field) // Cannot compare Type directly as field may be invalid (nil). if field.Kind() == reflect.Slice && field.Type() == typeObjSlice { // TODO Handle getters that return []qml.Object. // TODO Handle other GoValue slices (!= []qml.Object). resultdv.dataType = C.DTListProperty *(*unsafe.Pointer)(unsafe.Pointer(&resultdv.data)) = C.newListProperty(foldp, C.intptr_t(reflectIndex), C.intptr_t(setIndex)) return } fieldk := field.Kind() if fieldk == reflect.Slice || fieldk == reflect.Struct && field.Type() != typeRGBA { if field.CanAddr() { field = field.Addr() } else if !hashable(field.Interface()) { t := reflect.ValueOf(fold.gvalue).Type() for t.Kind() == reflect.Ptr { t = t.Elem() } panic(fmt.Sprintf("cannot access unaddressable and unhashable struct value on interface field %s.%s; value: %#v", t.Name(), t.Field(int(reflectIndex)).Name, field.Interface())) } } var gvalue interface{} if field.IsValid() { gvalue = field.Interface() } // TODO Strings are being passed in an unsafe manner here. There is a // small chance that the field is changed and the garbage collector is run // before C++ has a chance to look at the data. We can solve this problem // by queuing up values in a stack, and cleaning the stack when the // idle timer fires next. packDataValue(gvalue, resultdv, fold.engine, jsOwner) }
func (i *imagelist) Append(img *image.RGBA) { id := C.toImageListImage( unsafe.Pointer(pixelData(img)), C.intptr_t(img.Rect.Dx()), C.intptr_t(img.Rect.Dy()), C.intptr_t(img.Stride)) i.list = append(i.list, id) }
func (i *imagelist) Append(img *image.RGBA) { i.list = append(i.list, C.unscaledBitmap(unsafe.Pointer(img), C.intptr_t(img.Rect.Dx()), C.intptr_t(img.Rect.Dy()))) i.width = append(i.width, img.Rect.Dx()) i.height = append(i.height, img.Rect.Dy()) }
func dobasecommitResize(id C.id, c *allocation, d *sizing) { C.moveControl(id, C.intptr_t(c.x), C.intptr_t(c.y), C.intptr_t(c.width), C.intptr_t(c.height)) }
func (e *EventSource) SetData(data uintptr) { C.al_set_event_source_data((*C.ALLEGRO_EVENT_SOURCE)(unsafe.Pointer(e)), C.intptr_t(data)) }
func (c *controlSingleObject) xresize(x int, y int, width int, height int, d *sizing) { C.moveControl(c.id, C.intptr_t(x), C.intptr_t(y), C.intptr_t(width), C.intptr_t(height)) }
combobox := C.makeCombobox(toBOOL(alternate)) applyStandardControlFont(combobox) addControl(parentWindow, combobox) return combobox }, show: controlShow, hide: controlHide, text: func(what C.id, alternate bool) C.id { return C.comboboxText(what, toBOOL(alternate)) }, append: func(id C.id, what string, alternate bool) { C.comboboxAppend(id, toBOOL(alternate), toNSString(what)) }, insertBefore: func(id C.id, what string, before int, alternate bool) { C.comboboxInsertBefore(id, toBOOL(alternate), toNSString(what), C.intptr_t(before)) }, selIndex: func(id C.id) int { return int(C.comboboxSelectedIndex(id)) }, delete: func(id C.id, index int) { C.comboboxDelete(id, C.intptr_t(index)) }, len: func(id C.id) int { return int(C.comboboxLen(id)) }, }, c_lineedit: &classData{ make: func(parentWindow C.id, alternate bool, s *sysData) C.id { lineedit := C.makeLineEdit(toBOOL(alternate)) applyStandardControlFont(lineedit)
func (t *table) Select(index int) { t.RLock() defer t.RUnlock() C.tableSelect(t.id, C.intptr_t(index)) }
func (a *area) OpenTextFieldAt(x, y int) { if x < 0 || x >= a.width || y < 0 || y >= a.height { panic(fmt.Errorf("point (%d,%d) outside Area in Area.OpenTextFieldAt()", x, y)) } C.areaTextFieldOpen(a.id, a.textfield, C.intptr_t(x), C.intptr_t(y)) }
func (a *area) SetSize(width, height int) { a.width = width a.height = height // set the frame size to set the area's effective size on the Cocoa side C.moveControl(a.id, 0, 0, C.intptr_t(a.width), C.intptr_t(a.height)) }
func (s *spinbox) resize(x int, y int, width int, height int, d *sizing) { // TODO C.moveControl(s.textfield(), C.intptr_t(x), C.intptr_t(y), C.intptr_t(width-20), C.intptr_t(height)) C.moveControl(s.stepper(), C.intptr_t(x+width-15), C.intptr_t(y), C.intptr_t(15), C.intptr_t(height)) }