func (tw *TabWidget) onResize(lParam uintptr) { r := win.RECT{0, 0, win.GET_X_LPARAM(lParam), win.GET_Y_LPARAM(lParam)} if !win.MoveWindow(tw.hWndTab, r.Left, r.Top, r.Right-r.Left, r.Bottom-r.Top, true) { lastError("MoveWindow") return } tw.resizePages() }
func (wb *WindowBase) publishMouseEvent(publisher *MouseEventPublisher, wParam, lParam uintptr) { x := int(win.GET_X_LPARAM(lParam)) y := int(win.GET_Y_LPARAM(lParam)) var button MouseButton switch true { case wParam&win.MK_LBUTTON > 0: button = LeftButton case wParam&win.MK_MBUTTON > 0: button = MiddleButton case wParam&win.MK_RBUTTON > 0: button = RightButton } publisher.Publish(x, y, button) }
func (tv *TableView) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { switch msg { case win.WM_ERASEBKGND: if tv.lastColumnStretched && !tv.inEraseBkgnd { tv.inEraseBkgnd = true defer func() { tv.inEraseBkgnd = false }() tv.StretchLastColumn() } return 1 case win.WM_GETDLGCODE: if wParam == win.VK_RETURN { return win.DLGC_WANTALLKEYS } case win.WM_LBUTTONDOWN, win.WM_RBUTTONDOWN, win.WM_LBUTTONDBLCLK, win.WM_RBUTTONDBLCLK: var hti win.LVHITTESTINFO hti.Pt = win.POINT{win.GET_X_LPARAM(lParam), win.GET_Y_LPARAM(lParam)} tv.SendMessage(win.LVM_HITTEST, 0, uintptr(unsafe.Pointer(&hti))) if hti.Flags == win.LVHT_NOWHERE && tv.SingleItemSelection() { // We keep the current item, if in single item selection mode. tv.SetFocus() return 0 } switch msg { case win.WM_LBUTTONDOWN, win.WM_RBUTTONDOWN: if hti.Flags == win.LVHT_ONITEMSTATEICON && tv.itemChecker != nil && tv.CheckBoxes() { tv.toggleItemChecked(int(hti.IItem)) } } case win.WM_KEYDOWN: if wParam == win.VK_SPACE && tv.currentIndex > -1 && tv.itemChecker != nil && tv.CheckBoxes() { tv.toggleItemChecked(tv.currentIndex) } case win.WM_NOTIFY: switch int32(((*win.NMHDR)(unsafe.Pointer(lParam))).Code) { case win.LVN_GETDISPINFO: di := (*win.NMLVDISPINFO)(unsafe.Pointer(lParam)) row := int(di.Item.IItem) col := tv.fromLVColIdx(di.Item.ISubItem) if di.Item.Mask&win.LVIF_TEXT > 0 { var text string switch val := tv.model.Value(row, col).(type) { case string: text = val case float32: prec := tv.columns.items[col].precision if prec == 0 { prec = 2 } text = FormatFloatGrouped(float64(val), prec) case float64: prec := tv.columns.items[col].precision if prec == 0 { prec = 2 } text = FormatFloatGrouped(val, prec) case time.Time: if val.Year() > 1601 { text = val.Format(tv.columns.items[col].format) } case *big.Rat: prec := tv.columns.items[col].precision if prec == 0 { prec = 2 } text = formatBigRatGrouped(val, prec) default: text = fmt.Sprintf(tv.columns.items[col].format, val) } utf16 := syscall.StringToUTF16(text) buf := (*[264]uint16)(unsafe.Pointer(di.Item.PszText)) max := mini(len(utf16), int(di.Item.CchTextMax)) copy((*buf)[:], utf16[:max]) (*buf)[max-1] = 0 } if tv.imageProvider != nil && di.Item.Mask&win.LVIF_IMAGE > 0 { if image := tv.imageProvider.Image(row); image != nil { if tv.hIml == 0 { tv.applyImageListForImage(image) } di.Item.IImage = imageIndexMaybeAdd( image, tv.hIml, tv.usingSysIml, tv.imageUintptr2Index, tv.filePath2IconIndex) } } if di.Item.StateMask&win.LVIS_STATEIMAGEMASK > 0 && tv.itemChecker != nil { checked := tv.itemChecker.Checked(row) if checked { di.Item.State = 0x2000 } else { di.Item.State = 0x1000 } } case win.NM_CUSTOMDRAW: if tv.alternatingRowBGColor != defaultTVRowBGColor { nmlvcd := (*win.NMLVCUSTOMDRAW)(unsafe.Pointer(lParam)) switch nmlvcd.Nmcd.DwDrawStage { case win.CDDS_PREPAINT: return win.CDRF_NOTIFYITEMDRAW case win.CDDS_ITEMPREPAINT: if nmlvcd.Nmcd.DwItemSpec%2 == 1 { /*if tv.hasDarkAltBGColor && nmlvcd.Nmcd.UItemState&win.CDIS_HOT == 0 && tv.SendMessage(win.LVM_GETITEMSTATE, nmlvcd.Nmcd.DwItemSpec, win.LVIS_SELECTED) == 0 && int32(tv.SendMessage(win.LVM_GETSELECTEDCOLUMN, 0, 0)) != nmlvcd.ISubItem { fmt.Printf("selcol: %d, subitem: %d\n", int32(tv.SendMessage(win.LVM_GETSELECTEDCOLUMN, 0, 0)), nmlvcd.ISubItem) nmlvcd.ClrText = white }*/ nmlvcd.ClrTextBk = win.COLORREF(tv.alternatingRowBGColor) } return win.CDRF_NOTIFYSUBITEMDRAW case win.CDDS_ITEMPREPAINT | win.CDDS_SUBITEM: if nmlvcd.Nmcd.DwItemSpec%2 == 1 && tv.hasDarkAltBGColor && nmlvcd.Nmcd.UItemState&win.CDIS_HOT == 0 && tv.SendMessage(win.LVM_GETITEMSTATE, nmlvcd.Nmcd.DwItemSpec, win.LVIS_SELECTED) == 0 && int32(tv.SendMessage(win.LVM_GETSELECTEDCOLUMN, 0, 0)) != nmlvcd.ISubItem { nmlvcd.ClrText = white } return win.CDRF_NEWFONT } } return win.CDRF_DODEFAULT case win.LVN_COLUMNCLICK: nmlv := (*win.NMLISTVIEW)(unsafe.Pointer(lParam)) col := tv.fromLVColIdx(nmlv.ISubItem) tv.columnClickedPublisher.Publish(col) if sorter, ok := tv.model.(Sorter); ok && sorter.ColumnSortable(col) { prevCol := sorter.SortedColumn() var order SortOrder if col != prevCol || sorter.SortOrder() == SortDescending { order = SortAscending } else { order = SortDescending } tv.sortedColumnIndex = col tv.sortOrder = order sorter.Sort(col, order) } case win.LVN_ITEMCHANGED: nmlv := (*win.NMLISTVIEW)(unsafe.Pointer(lParam)) selectedNow := nmlv.UNewState&win.LVIS_SELECTED > 0 selectedBefore := nmlv.UOldState&win.LVIS_SELECTED > 0 if selectedNow && !selectedBefore { tv.currentIndex = int(nmlv.IItem) if tv.itemStateChangedEventDelay > 0 { tv.delayedCurrentIndexChangedCanceled = false if 0 == win.SetTimer( tv.hWnd, tableViewCurrentIndexChangedTimerId, uint32(tv.itemStateChangedEventDelay), 0) { lastError("SetTimer") } } else { tv.currentIndexChangedPublisher.Publish() } } if !tv.SingleItemSelection() { tv.updateSelectedIndexes() } case win.LVN_ITEMACTIVATE: nmia := (*win.NMITEMACTIVATE)(unsafe.Pointer(lParam)) if tv.itemStateChangedEventDelay > 0 { tv.delayedCurrentIndexChangedCanceled = true } tv.SetCurrentIndex(int(nmia.IItem)) tv.currentIndexChangedPublisher.Publish() tv.itemActivatedPublisher.Publish() } case win.WM_TIMER: switch wParam { case tableViewCurrentIndexChangedTimerId: if !tv.delayedCurrentIndexChangedCanceled { tv.currentIndexChangedPublisher.Publish() } case tableViewSelectedIndexesChangedTimerId: tv.selectedIndexesChangedPublisher.Publish() } } return tv.WidgetBase.WndProc(hwnd, msg, wParam, lParam) }
// WndProc is the window procedure of the window. // // When implementing your own WndProc to add or modify behavior, call the // WndProc of the embedded window for messages you don't handle yourself. func (wb *WindowBase) WndProc(hwnd win.HWND, msg uint32, wParam, lParam uintptr) uintptr { switch msg { case win.WM_ERASEBKGND: if wb.background == nil { break } canvas, err := newCanvasFromHDC(win.HDC(wParam)) if err != nil { break } defer canvas.Dispose() if err := canvas.FillRectangle(wb.background, wb.ClientBounds()); err != nil { break } return 1 case win.WM_LBUTTONDOWN, win.WM_MBUTTONDOWN, win.WM_RBUTTONDOWN: if msg == win.WM_LBUTTONDOWN && wb.origWndProcPtr == 0 { // Only call SetCapture if this is no subclassed control. // (Otherwise e.g. WM_COMMAND(BN_CLICKED) would no longer // be generated for PushButton.) win.SetCapture(wb.hWnd) } wb.publishMouseEvent(&wb.mouseDownPublisher, wParam, lParam) case win.WM_LBUTTONUP, win.WM_MBUTTONUP, win.WM_RBUTTONUP: if msg == win.WM_LBUTTONUP && wb.origWndProcPtr == 0 { // See WM_LBUTTONDOWN for why we require origWndProcPtr == 0 here. if !win.ReleaseCapture() { lastError("ReleaseCapture") } } wb.publishMouseEvent(&wb.mouseUpPublisher, wParam, lParam) case win.WM_MOUSEMOVE: wb.publishMouseEvent(&wb.mouseMovePublisher, wParam, lParam) case win.WM_SETCURSOR: if wb.cursor != nil { win.SetCursor(wb.cursor.handle()) return 0 } case win.WM_CONTEXTMENU: sourceWindow := windowFromHandle(win.HWND(wParam)) if sourceWindow == nil { break } x := win.GET_X_LPARAM(lParam) y := win.GET_Y_LPARAM(lParam) contextMenu := sourceWindow.ContextMenu() var handle win.HWND if widget, ok := sourceWindow.(Widget); ok { handle = ancestor(widget).Handle() } else { handle = sourceWindow.Handle() } if contextMenu != nil { win.TrackPopupMenuEx( contextMenu.hMenu, win.TPM_NOANIMATION, x, y, handle, nil) return 0 } case win.WM_KEYDOWN: wb.handleKeyDown(wParam, lParam) case win.WM_KEYUP: wb.handleKeyUp(wParam, lParam) case win.WM_SIZE, win.WM_SIZING: wb.sizeChangedPublisher.Publish() case win.WM_DESTROY: if wb.origWndProcPtr != 0 { // As we subclass all windows of system classes, we prevented the // clean-up code in the WM_NCDESTROY handlers of some windows from // being called. To fix this, we restore the original window // procedure here. win.SetWindowLongPtr(wb.hWnd, win.GWLP_WNDPROC, wb.origWndProcPtr) } delete(hwnd2WindowBase, hwnd) wb.window.Dispose() wb.hWnd = 0 } if wb.origWndProcPtr != 0 { return win.CallWindowProc(wb.origWndProcPtr, hwnd, msg, wParam, lParam) } return win.DefWindowProc(hwnd, msg, wParam, lParam) }