Esempio n. 1
0
func (slct *Select) Show(workarea xrect.Rect, tabCompleteType int,
	groups []*SelectShowGroup, data interface{}) bool {

	if slct.showing {
		return false
	}

	// if there aren't any groups, we obviously don't need to show anything.
	if len(groups) == 0 {
		return false
	}

	// So maybe there are groups, but there aren't any items...
	foundItem := false
	for _, group := range groups {
		if len(group.items) > 0 {
			foundItem = true
			break
		}
	}
	if !foundItem {
		return false
	}

	slct.groups = groups
	slct.tabComplete = tabCompleteType

	slct.win.Stack(xproto.StackModeAbove)
	slct.input.Reset()

	// Position the initial list of items with no filter.
	slct.FilterItems("")

	// Create some short aliases and start computing the geometry of the
	// prompt window.
	bs := slct.theme.BorderSize
	pad := slct.theme.Padding

	inpHeight := slct.input.Geom.Height()
	height := 2*(bs+pad) + inpHeight + bs
	maxFontWidth := 0
	didGroupSpacing := false
	for _, group := range slct.groups {
		if len(group.items) > 0 && group.hasGroup() {
			maxFontWidth = misc.Max(maxFontWidth, group.win.Geom.Width())
			height += group.win.Geom.Height() + slct.theme.GroupSpacing
			didGroupSpacing = true
		}
		for _, item := range group.items {
			maxFontWidth = misc.Max(maxFontWidth, item.regular.Geom.Width())
			height += item.regular.Geom.Height() + itemTopSpace + itemBotSpace
		}
	}

	if didGroupSpacing {
		height -= slct.theme.GroupSpacing
	}
	maxWidth := int(float64(workarea.Width()) * 0.8)
	width := misc.Min(maxWidth, maxFontWidth+2*(bs+pad))

	// position the damn window based on its width/height (i.e., center it)
	posx := workarea.X() + workarea.Width()/2 - width/2
	posy := workarea.Y() + workarea.Height()/2 - height/2

	// Issue the configure requests. We also need to adjust the borders.
	slct.win.MoveResize(posx, posy, width, height)
	slct.bInp.MoveResize(0, bs+inpHeight, width, bs)
	slct.bTop.Resize(width, bs)
	slct.bBot.MoveResize(0, height-bs, width, bs)
	slct.bLft.Resize(bs, height)
	slct.bRht.MoveResize(width-bs, 0, bs, height)

	slct.showing = true
	slct.data = data
	slct.selected = -1
	slct.win.Map()
	slct.bInp.Focus()

	return true
}
Esempio n. 2
0
// Show will map and show the slice of items provided.
//
// 'workarea' is the rectangle to position the prompt window in. (i.e.,
// typically the rectangle of the monitor to place it on.)
//
// 'keyStr' is an optional parameter. If this prompt is shown in
// response to a keybinding, then keyStr should be the keybinding used.
// If there are modifiers used in the keyStr, the prompt will automatically
// close if all of the modifiers are released. (This is the "alt-tab"
// functionality.)
// Note that if you don't want this auto-closing feature, simply leave keyStr
// blank, even if the prompt is shown in response to a key binding.
//
// Show returns false if the prompt cannot be shown for some reason.
func (cycle *Cycle) Show(workarea xrect.Rect,
	keyStr string, items []*CycleItem) bool {

	if cycle.showing {
		return false
	}

	// If there are no items, obviously quit.
	if len(items) == 0 {
		return false
	}

	// Note that SmartGrab is smart and avoids races. Check it out
	// in xgbutil/keybind.go if you're interested.
	// This makes it impossible to press and release alt-tab too quickly
	// to have it not register.
	if cycle.config.Grab {
		if err := keybind.SmartGrab(cycle.X, cycle.X.Dummy()); err != nil {
			logger.Warning.Printf(
				"Could not grab keyboard for prompt cycle: %s", err)
			return false
		}
	}

	// Save the list of cycle items (this how we know when to cycle between
	// them). Namely, cycle.selected is an index to this list.
	cycle.items = items

	// Save the modifiers used, if any.
	cycle.grabMods, _, _ = keybind.ParseString(cycle.X, keyStr)

	// Put the prompt window on top of the window stack.
	cycle.win.Stack(xproto.StackModeAbove)

	// Create some short aliases and start computing the geometry of the
	// cycle window.
	bs := cycle.theme.BorderSize
	cbs := cycle.theme.IconBorderSize
	is := cycle.theme.IconSize
	pad := cycle.theme.Padding

	maxWidth := int(float64(workarea.Width()) * 0.8)
	x, y := bs+pad, bs+pad+cbs+cycle.fontHeight
	width := 2 * (bs + pad)
	height := (2 * (bs + pad + cbs)) + is + cbs + cycle.fontHeight
	maxFontWidth := 0

	widthStatic := false // when true, we stop increasing width
	for _, item := range items {
		maxFontWidth = misc.Max(maxFontWidth, item.text.Geom.Width())

		// Check if we should move on to the next row.
		if x+(is+(2*cbs))+pad+bs > maxWidth {
			x = bs + pad
			y += is + (2 * cbs)
			height += is + (2 * cbs)
			widthStatic = true
		}

		// Position the icon window and map its active version or its
		// inactive version if it's iconified.
		item.show(x, y)

		// Only increase the width if we're still adding icons to the first row.
		if !widthStatic {
			width += is + (2 * cbs)
		}
		x += is + (2 * cbs)
	}

	// If the computed width is less than the max font width, then increase
	// the width of the prompt to fit the longest window title.
	// Forcefully cap it as the maxWidth, though.
	if maxFontWidth+2*(pad+bs) > width {
		width = misc.Min(maxWidth, maxFontWidth+2*(pad+bs))
	}

	// position the damn window based on its width/height (i.e., center it)
	posx := workarea.X() + workarea.Width()/2 - width/2
	posy := workarea.Y() + workarea.Height()/2 - height/2

	// Issue the configure requests. We also need to adjust the borders.
	cycle.win.MoveResize(posx, posy, width, height)
	cycle.bTop.Resize(width, bs)
	cycle.bBot.MoveResize(0, height-bs, width, bs)
	cycle.bLft.Resize(bs, height)
	cycle.bRht.MoveResize(width-bs, 0, bs, height)

	cycle.showing = true
	cycle.selected = -1
	cycle.win.Map()

	return true
}