github.com/secoba/wails/v2@v2.6.4/internal/frontend/desktop/windows/winc/toolbar.go (about)

     1  //go:build windows
     2  
     3  /*
     4   * Copyright (C) 2019 The Winc Authors. All Rights Reserved.
     5   */
     6  
     7  package winc
     8  
     9  import (
    10  	"syscall"
    11  	"unsafe"
    12  
    13  	"github.com/secoba/wails/v2/internal/frontend/desktop/windows/winc/w32"
    14  )
    15  
    16  type Toolbar struct {
    17  	ControlBase
    18  	iml *ImageList
    19  
    20  	buttons []*ToolButton
    21  }
    22  
    23  type ToolButton struct {
    24  	tb *Toolbar
    25  
    26  	text      string
    27  	enabled   bool
    28  	checkable bool
    29  	checked   bool
    30  	image     int
    31  
    32  	onClick EventManager
    33  }
    34  
    35  func (bt *ToolButton) OnClick() *EventManager {
    36  	return &bt.onClick
    37  }
    38  
    39  func (bt *ToolButton) update() { bt.tb.update(bt) }
    40  
    41  func (bt *ToolButton) IsSeparator() bool { return bt.text == "-" }
    42  func (bt *ToolButton) SetSeparator()     { bt.text = "-" }
    43  
    44  func (bt *ToolButton) Enabled() bool     { return bt.enabled }
    45  func (bt *ToolButton) SetEnabled(b bool) { bt.enabled = b; bt.update() }
    46  
    47  func (bt *ToolButton) Checkable() bool     { return bt.checkable }
    48  func (bt *ToolButton) SetCheckable(b bool) { bt.checkable = b; bt.update() }
    49  
    50  func (bt *ToolButton) Checked() bool     { return bt.checked }
    51  func (bt *ToolButton) SetChecked(b bool) { bt.checked = b; bt.update() }
    52  
    53  func (bt *ToolButton) Text() string     { return bt.text }
    54  func (bt *ToolButton) SetText(s string) { bt.text = s; bt.update() }
    55  
    56  func (bt *ToolButton) Image() int     { return bt.image }
    57  func (bt *ToolButton) SetImage(i int) { bt.image = i; bt.update() }
    58  
    59  // NewHToolbar creates horizontal toolbar with text on same line as image.
    60  func NewHToolbar(parent Controller) *Toolbar {
    61  	return newToolbar(parent, w32.CCS_NODIVIDER|w32.TBSTYLE_FLAT|w32.TBSTYLE_TOOLTIPS|w32.TBSTYLE_WRAPABLE|
    62  		w32.WS_CHILD|w32.TBSTYLE_LIST)
    63  }
    64  
    65  // NewToolbar creates toolbar with text below the image.
    66  func NewToolbar(parent Controller) *Toolbar {
    67  	return newToolbar(parent, w32.CCS_NODIVIDER|w32.TBSTYLE_FLAT|w32.TBSTYLE_TOOLTIPS|w32.TBSTYLE_WRAPABLE|
    68  		w32.WS_CHILD /*|w32.TBSTYLE_TRANSPARENT*/)
    69  }
    70  
    71  func newToolbar(parent Controller, style uint) *Toolbar {
    72  	tb := new(Toolbar)
    73  
    74  	tb.InitControl("ToolbarWindow32", parent, 0, style)
    75  
    76  	exStyle := w32.SendMessage(tb.hwnd, w32.TB_GETEXTENDEDSTYLE, 0, 0)
    77  	exStyle |= w32.TBSTYLE_EX_DRAWDDARROWS | w32.TBSTYLE_EX_MIXEDBUTTONS
    78  	w32.SendMessage(tb.hwnd, w32.TB_SETEXTENDEDSTYLE, 0, exStyle)
    79  	RegMsgHandler(tb)
    80  
    81  	tb.SetFont(DefaultFont)
    82  	tb.SetPos(0, 0)
    83  	tb.SetSize(200, 40)
    84  
    85  	return tb
    86  }
    87  
    88  func (tb *Toolbar) SetImageList(imageList *ImageList) {
    89  	w32.SendMessage(tb.hwnd, w32.TB_SETIMAGELIST, 0, uintptr(imageList.Handle()))
    90  	tb.iml = imageList
    91  }
    92  
    93  func (tb *Toolbar) initButton(btn *ToolButton, state, style *byte, image *int32, text *uintptr) {
    94  	*style |= w32.BTNS_AUTOSIZE
    95  
    96  	if btn.checked {
    97  		*state |= w32.TBSTATE_CHECKED
    98  	}
    99  
   100  	if btn.enabled {
   101  		*state |= w32.TBSTATE_ENABLED
   102  	}
   103  
   104  	if btn.checkable {
   105  		*style |= w32.BTNS_CHECK
   106  	}
   107  
   108  	if len(btn.Text()) > 0 {
   109  		*style |= w32.BTNS_SHOWTEXT
   110  	}
   111  
   112  	if btn.IsSeparator() {
   113  		*style = w32.BTNS_SEP
   114  	}
   115  
   116  	*image = int32(btn.Image())
   117  	*text = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(btn.Text())))
   118  }
   119  
   120  func (tb *Toolbar) update(btn *ToolButton) {
   121  	tbbi := w32.TBBUTTONINFO{
   122  		DwMask: w32.TBIF_IMAGE | w32.TBIF_STATE | w32.TBIF_STYLE | w32.TBIF_TEXT,
   123  	}
   124  
   125  	tbbi.CbSize = uint32(unsafe.Sizeof(tbbi))
   126  
   127  	var i int
   128  	for i = range tb.buttons {
   129  		if tb.buttons[i] == btn {
   130  			break
   131  		}
   132  	}
   133  
   134  	tb.initButton(btn, &tbbi.FsState, &tbbi.FsStyle, &tbbi.IImage, &tbbi.PszText)
   135  	if w32.SendMessage(tb.hwnd, w32.TB_SETBUTTONINFO, uintptr(i), uintptr(unsafe.Pointer(&tbbi))) == 0 {
   136  		panic("SendMessage(TB_SETBUTTONINFO) failed")
   137  	}
   138  }
   139  
   140  func (tb *Toolbar) AddSeparator() {
   141  	tb.AddButton("-", 0)
   142  }
   143  
   144  // AddButton creates and adds button to the toolbar. Use returned toolbutton to setup OnClick event.
   145  func (tb *Toolbar) AddButton(text string, image int) *ToolButton {
   146  	bt := &ToolButton{
   147  		tb:      tb, // points to parent
   148  		text:    text,
   149  		image:   image,
   150  		enabled: true,
   151  	}
   152  	tb.buttons = append(tb.buttons, bt)
   153  	index := len(tb.buttons) - 1
   154  
   155  	tbb := w32.TBBUTTON{
   156  		IdCommand: int32(index),
   157  	}
   158  
   159  	tb.initButton(bt, &tbb.FsState, &tbb.FsStyle, &tbb.IBitmap, &tbb.IString)
   160  	w32.SendMessage(tb.hwnd, w32.TB_BUTTONSTRUCTSIZE, uintptr(unsafe.Sizeof(tbb)), 0)
   161  
   162  	if w32.SendMessage(tb.hwnd, w32.TB_INSERTBUTTON, uintptr(index), uintptr(unsafe.Pointer(&tbb))) == w32.FALSE {
   163  		panic("SendMessage(TB_ADDBUTTONS)")
   164  	}
   165  
   166  	w32.SendMessage(tb.hwnd, w32.TB_AUTOSIZE, 0, 0)
   167  	return bt
   168  }
   169  
   170  func (tb *Toolbar) WndProc(msg uint32, wparam, lparam uintptr) uintptr {
   171  	switch msg {
   172  	case w32.WM_COMMAND:
   173  		switch w32.HIWORD(uint32(wparam)) {
   174  		case w32.BN_CLICKED:
   175  			id := uint16(w32.LOWORD(uint32(wparam)))
   176  			btn := tb.buttons[id]
   177  			btn.onClick.Fire(NewEvent(tb, nil))
   178  		}
   179  	}
   180  	return w32.DefWindowProc(tb.hwnd, msg, wparam, lparam)
   181  }