5
// Mike KrĆ¼ger <mkrueger@xamarin.com>
7
// Copyright (c) 2012 Xamarin Inc. (http://xamarin.com)
9
// Permission is hereby granted, free of charge, to any person obtaining a copy
10
// of this software and associated documentation files (the "Software"), to deal
11
// in the Software without restriction, including without limitation the rights
12
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
// copies of the Software, and to permit persons to whom the Software is
14
// furnished to do so, subject to the following conditions:
16
// The above copyright notice and this permission notice shall be included in
17
// all copies or substantial portions of the Software.
19
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29
using System.Collections.Generic;
30
using MonoDevelop.Components;
33
using MonoDevelop.Components.Commands;
34
using MonoDevelop.Ide;
35
using MonoDevelop.Core;
37
namespace MonoDevelop.Components.MainToolbar
39
class ButtonBar : EventBox, ICommandBar
41
const int SeparatorSpacing = 6;
42
List<ButtonBarButton> buttons = new List<ButtonBarButton> ();
43
ButtonBarButton[] visibleButtons;
45
Gdk.Pixbuf[] btnNormalOriginal;
46
Gdk.Pixbuf[] btnPressedOriginal;
47
Gdk.Pixbuf[] btnNormal;
48
Gdk.Pixbuf[] btnPressed;
50
ButtonBarButton pushedButton;
51
object lastCommandTarget;
52
int currentImagesHeight;
56
WidgetFlags |= Gtk.WidgetFlags.AppPaintable;
57
VisibleWindow = false;
58
Events |= EventMask.ButtonPressMask | EventMask.ButtonReleaseMask;
60
btnNormalOriginal = new Gdk.Pixbuf[] {
61
Gdk.Pixbuf.LoadFromResource ("btDebugBase-LeftCap-Normal.png"),
62
Gdk.Pixbuf.LoadFromResource ("btDebugBase-MidCap-Normal.png"),
63
Gdk.Pixbuf.LoadFromResource ("btDebugBase-RightCap-Normal.png")
66
btnPressedOriginal = new Gdk.Pixbuf[] {
67
Gdk.Pixbuf.LoadFromResource ("btDebugBase-LeftCap-Pressed.png"),
68
Gdk.Pixbuf.LoadFromResource ("btDebugBase-MidCap-Pressed.png"),
69
Gdk.Pixbuf.LoadFromResource ("btDebugBase-RightCap-Pressed.png")
71
btnNormal = new Pixbuf[btnNormalOriginal.Length];
72
btnPressed = new Pixbuf[btnNormalOriginal.Length];
76
void ScaleImages (int newHeight)
78
if (currentImagesHeight == newHeight)
81
currentImagesHeight = newHeight;
82
for (int n=0; n<btnNormalOriginal.Length; n++) {
83
if (btnNormal[n] != null)
84
btnNormal[n].Dispose ();
85
btnNormal[n] = ExpandImageVertically (btnNormalOriginal[n], newHeight);
87
for (int n=0; n<btnPressedOriginal.Length; n++) {
88
if (btnPressed[n] != null)
89
btnPressed[n].Dispose ();
90
btnPressed[n] = ExpandImageVertically (btnPressedOriginal[n], newHeight);
94
ButtonBarButton[] VisibleButtons {
96
if (visibleButtons == null)
97
visibleButtons = buttons.Where (b => b.Visible || b.IsSeparator).ToArray ();
98
return visibleButtons;
102
StateType leaveState = StateType.Normal;
103
protected override bool OnEnterNotifyEvent (EventCrossing evnt)
106
return base.OnEnterNotifyEvent (evnt);
109
protected override bool OnLeaveNotifyEvent (EventCrossing evnt)
112
State = StateType.Normal;
113
return base.OnLeaveNotifyEvent (evnt);
116
protected override bool OnButtonPressEvent (EventButton evnt)
118
if (evnt.Button == 1) {
119
pushedButton = VisibleButtons.FirstOrDefault (b => b.Allocation.Contains (Allocation.X + (int)evnt.X, Allocation.Y + (int)evnt.Y));
120
if (pushedButton != null && pushedButton.Enabled)
121
State = StateType.Selected;
126
protected override bool OnButtonReleaseEvent (EventButton evnt)
128
if (State == StateType.Selected && pushedButton != null)
129
IdeApp.CommandService.DispatchCommand (pushedButton.CommandId, null, lastCommandTarget, CommandSource.MainToolbar);
130
State = StateType.Prelight;
131
leaveState = StateType.Normal;
136
protected override bool OnQueryTooltip (int x, int y, bool keyboard_tooltip, Tooltip tooltip)
138
var button = VisibleButtons.FirstOrDefault (b => b.Allocation.Contains (Allocation.X + (int)x, Allocation.Y + (int)y));
139
if (button != null) {
140
tooltip.Text = button.Tooltip;
141
var rect = button.Allocation;
142
rect.Offset (-Allocation.X, -Allocation.Y);
143
tooltip.TipArea = rect;
153
visibleButtons = null;
158
public void Add (string commandId)
160
ButtonBarButton b = new ButtonBarButton (commandId);
161
var ci = IdeApp.CommandService.GetCommandInfo (commandId, new CommandTargetRoute (lastCommandTarget));
163
UpdateButton (b, ci);
165
visibleButtons = null;
169
public void AddSeparator ()
171
buttons.Add (new ButtonBarButton (null));
172
visibleButtons = null;
176
protected override void OnSizeRequested (ref Requisition requisition)
178
base.OnSizeRequested (ref requisition);
179
requisition.Width = VisibleButtons.Sum (b => b.Visible ? (!b.IsSeparator ? btnNormalOriginal[0].Width : SeparatorSpacing) : 0);
180
requisition.Height = btnNormalOriginal[0].Height;
183
protected override bool OnExposeEvent (EventExpose evnt)
185
ScaleImages (Allocation.Height);
187
using (var context = Gdk.CairoHelper.Create (evnt.Window)) {
188
double x = Allocation.X, y = Allocation.Y;
189
for (int i = 0; i < VisibleButtons.Length; i++) {
190
bool nextIsSeparator = (i < VisibleButtons.Length - 1 && VisibleButtons[i + 1].IsSeparator) || i == visibleButtons.Length - 1;
191
bool lastWasSeparator = (i > 0 && VisibleButtons[i - 1].IsSeparator) || i == 0;
192
ButtonBarButton button = VisibleButtons [i];
193
if (button.IsSeparator) {
194
if (!lastWasSeparator)
195
x += SeparatorSpacing;
198
Gdk.Pixbuf[] images = State == StateType.Selected && pushedButton == button ? btnPressed : btnNormal;
199
Gdk.Pixbuf img = images [lastWasSeparator ? 0 : nextIsSeparator ? 2 : 1];
200
Gdk.CairoHelper.SetSourcePixbuf (context, img, x, y);
203
button.Allocation = new Gdk.Rectangle ((int)x, (int)y, img.Width, img.Height);
205
var icon = ImageService.GetPixbuf (button.Image, IconSize.Menu);
207
if (!Sensitive || !button.Enabled)
208
iconCopy = ImageService.MakeTransparent (icon, 0.4);
209
Gdk.CairoHelper.SetSourcePixbuf (context, iconCopy, x + (img.Width - icon.Width) / 2, y + (img.Height - icon.Height) / 2);
211
if (iconCopy != icon)
216
return base.OnExposeEvent (evnt);
219
Gdk.Pixbuf ExpandImageVertically (Gdk.Pixbuf img, int newHeight)
221
if (newHeight <= img.Height)
223
var res = new Gdk.Pixbuf (img.Colorspace, img.HasAlpha, img.BitsPerSample, img.Width, newHeight);
224
var h1 = img.Height / 2;
225
var h2 = img.Height - h1;
226
res.Fill (0xff000000);
227
img.Composite (res, 0, h1, res.Width, newHeight - img.Height, 0, 0, 1, (double)newHeight / (double)img.Height, InterpType.Bilinear, 255);
228
img.Composite (res, 0, 0, img.Width, h1, 0, 0, 1, 1, InterpType.Bilinear, 255);
229
img.Composite (res, 0, newHeight - h2, img.Width, h2, 0, newHeight - img.Height, 1, 1, InterpType.Bilinear, 255);
233
public sealed class ClickEventArgs : EventArgs
235
public int Button { get; private set; }
237
public ClickEventArgs (int button)
239
this.Button = button;
243
#region ICommandBar implementation
244
void ICommandBar.Update (object activeTarget)
246
lastCommandTarget = activeTarget;
247
foreach (var b in buttons.Where (bu => !bu.IsSeparator)) {
248
var ci = IdeApp.CommandService.GetCommandInfo (b.CommandId, new CommandTargetRoute (activeTarget));
249
UpdateButton (b, ci);
253
void UpdateButton (ButtonBarButton b, CommandInfo ci)
255
if (ci.Icon != b.Image) {
259
if (ci.Visible != b.Visible) {
260
b.Visible = ci.Visible;
261
visibleButtons = null;
264
if (ci.Enabled != b.Enabled) {
265
b.Enabled = ci.Enabled;
268
if (ci.Description != b.Tooltip)
269
b.Tooltip = ci.Description;
272
void ICommandBar.SetEnabled (bool enabled)
279
class ButtonBarButton
281
public ButtonBarButton (string commandId)
283
this.CommandId = commandId;
286
public IconId Image { get; set; }
287
public string CommandId { get; set; }
288
internal bool Enabled { get; set; }
289
internal bool Visible { get; set; }
290
public string Tooltip { get; set; }
292
public Gdk.Rectangle Allocation;
294
public bool IsSeparator {
295
get { return CommandId == null; }