├── Ribbons.mds ├── Ribbons ├── ApplicationButton.cs ├── ApplicationMenu.cs ├── ApplicationMenuItem.cs ├── BaseButton.cs ├── Button.cs ├── ChangeLog ├── ColorScheme.cs ├── DropdownRibbonGroup.cs ├── ExtraEventBox.cs ├── FlowLayoutContainer.cs ├── Gallery.cs ├── GalleryPopupWindow.cs ├── GroupStyle.cs ├── GroupVariant.cs ├── KeyTip.cs ├── PageAddedHandler.cs ├── PageEventArgs.cs ├── PageMovedEventArgs.cs ├── PageMovedHandler.cs ├── PageRemovedHandler.cs ├── PageSelectedHandler.cs ├── Position.cs ├── QuickAccessToolbar.cs ├── Ribbon.cs ├── RibbonGroup.cs ├── Ribbons.mdp ├── SyntheticEventCrossing.cs ├── SyntheticWindow.cs ├── Theme.cs ├── Tile.cs ├── TileSelectedEventArgs.cs ├── TileSelectedHandler.cs ├── ToggleButton.cs ├── ToolBox.cs ├── ToolPack.cs ├── VariantsCombinaison.cs ├── VariantsCombinaisonSwitcher.cs └── gtk-gui │ ├── generated.cs │ ├── gui.stetic │ └── objects.xml ├── Sample ├── AssemblyInfo.cs ├── ChangeLog ├── DropdownGroupTest.cs ├── Main.cs ├── MainWindow.cs ├── Sample.mdp ├── SampleTile.cs └── VariantsCombinaisonTest.cs └── doc.html /Ribbons.mds: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Ribbons/ApplicationButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// 8 | /// A button used to display the application menu. This button has a theme different than all other buttons. 9 | /// 10 | public class ApplicationButton : BaseButton 11 | { 12 | protected const double lineWidth = 1.0; 13 | 14 | private ApplicationMenu appMenu; 15 | private bool menuOpened; 16 | private KeyTip keyTip; 17 | 18 | /// Fired when the button is clicked. 19 | [GLib.Signal("clicked")] 20 | public event EventHandler Clicked; 21 | 22 | public ApplicationMenu Menu 23 | { 24 | get { return appMenu; } 25 | } 26 | 27 | public KeyTip KeyTip 28 | { 29 | get { return keyTip; } 30 | set { keyTip = value; } 31 | } 32 | 33 | public ApplicationButton() 34 | { 35 | this.SetFlag (WidgetFlags.NoWindow); 36 | 37 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 38 | 39 | menuOpened = false; 40 | 41 | appMenu = new ApplicationMenu (this); 42 | appMenu.Hidden += appMenu_Hidden; 43 | 44 | HeightRequest = 36; 45 | WidthRequest = 36; 46 | 47 | this.enable = true; 48 | } 49 | 50 | /// Fires the Click event. 51 | public void Click () 52 | { 53 | if(enable && Clicked != null) Clicked (this, EventArgs.Empty); 54 | 55 | int x, y; 56 | ParentWindow.GetOrigin (out x, out y); 57 | x += Allocation.X; 58 | y += Allocation.Bottom; 59 | 60 | appMenu.ShowAt (x, y); 61 | menuOpened = true; 62 | QueueDraw (); 63 | } 64 | 65 | private void appMenu_Hidden (object sender, EventArgs args) 66 | { 67 | menuOpened = false; 68 | QueueDraw (); 69 | } 70 | 71 | protected override void BindedWidget_ButtonPressEvent (object sender, ButtonPressEventArgs evnt) 72 | { 73 | ProcessEvent (evnt.Event); 74 | } 75 | 76 | protected override void BindedWidget_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs evnt) 77 | { 78 | ProcessEvent (evnt.Event); 79 | Click (); 80 | } 81 | 82 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 83 | { 84 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 85 | 86 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 87 | cr.Clip (); 88 | Draw (cr); 89 | 90 | ((IDisposable)cr.Target).Dispose (); 91 | ((IDisposable)cr).Dispose (); 92 | 93 | return base.OnExposeEvent (evnt); 94 | } 95 | 96 | protected void Draw (Context cr) 97 | { 98 | Theme.ButtonState state = this.state; 99 | if(menuOpened) state = Theme.ButtonState.Pressed; 100 | theme.DrawApplicationButton (cr, Allocation, state, lineWidth, this); 101 | } 102 | 103 | public void ShowKeyTips () 104 | { 105 | if(keyTip != null) 106 | { 107 | Gdk.Rectangle alloc = Allocation; 108 | int x, y; 109 | GdkWindow.GetOrigin (out x, out y); 110 | keyTip.ShowAt (x + alloc.X + (alloc.Width >> 1), y + alloc.Y + (alloc.Height >> 1), 0.5, 0.5); 111 | } 112 | } 113 | 114 | public void HideKeyTips () 115 | { 116 | if(keyTip != null) 117 | { 118 | keyTip.Hide (); 119 | } 120 | } 121 | 122 | protected override bool OnButtonPressEvent (Gdk.EventButton evnt) 123 | { 124 | bool ret = base.OnButtonPressEvent (evnt); 125 | state = Theme.ButtonState.Pressed; 126 | if(!enable) state = Theme.ButtonState.Default; 127 | this.QueueDraw (); 128 | Click (); 129 | return ret; 130 | } 131 | 132 | protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt) 133 | { 134 | bool ret = base.OnButtonReleaseEvent (evnt); 135 | state = Theme.ButtonState.Hover; 136 | if(!enable) state = Theme.ButtonState.Default; 137 | this.QueueDraw (); 138 | return ret; 139 | } 140 | 141 | protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt) 142 | { 143 | bool ret = base.OnEnterNotifyEvent (evnt); 144 | state = Theme.ButtonState.Hover; 145 | if(!enable) state = Theme.ButtonState.Default; 146 | this.QueueDraw (); 147 | return ret; 148 | } 149 | 150 | protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt) 151 | { 152 | bool ret = base.OnLeaveNotifyEvent (evnt); 153 | state = Theme.ButtonState.Default; 154 | this.QueueDraw (); 155 | return ret; 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Ribbons/ApplicationMenu.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using Gtk; 5 | using Cairo; 6 | 7 | namespace Ribbons 8 | { 9 | /// 10 | /// The main menu of an application, displaying application-level commands, and documents list. 11 | /// 12 | public class ApplicationMenu : Container 13 | { 14 | private static readonly TimeSpan openTimeoutSec = new TimeSpan (0, 0, 0, 0, 300); 15 | 16 | private const int verticalWindowOffset = topPadding - space; 17 | private const double lineWidth = 1.0; 18 | private const int topPadding = 24; 19 | private const int borderWidth = 6; 20 | private const int space = 2; 21 | 22 | protected Theme theme = Theme.DefaultTheme; 23 | 24 | private ApplicationButton appBtn; 25 | private List items; 26 | private Widget defaultMenu; 27 | private int itemHeight; 28 | private Gdk.Size menuSize; 29 | 30 | private Button optionsBtn, exitBtn; 31 | private Widget activeMenu; 32 | 33 | private Gdk.Rectangle itemsAlloc; 34 | private int menuItemsColWidth; 35 | private int buttonsHeight; 36 | private int exitBtnWidth, optionsBtnWidth; 37 | private int visibleMenuItems; 38 | private bool activeMenuVisible; 39 | private bool optionsBtnVisible, exitBtnVisible; 40 | 41 | private Window win; 42 | 43 | public ApplicationButton ApplicationButton 44 | { 45 | get { return appBtn; } 46 | } 47 | 48 | public Button OptionsButton 49 | { 50 | get { return optionsBtn; } 51 | set 52 | { 53 | if(optionsBtn == value) return; 54 | if(optionsBtn != null) optionsBtn.Unparent (); 55 | optionsBtn = value; 56 | if(value != null) 57 | { 58 | value.DrawBackground = true; 59 | value.OpaqueBackground = true; 60 | value.Parent = this; 61 | value.Visible = true; 62 | } 63 | } 64 | } 65 | 66 | public Button ExitButton 67 | { 68 | get { return exitBtn; } 69 | set 70 | { 71 | if(exitBtn == value) return; 72 | if(exitBtn != null) exitBtn.Unparent (); 73 | exitBtn = value; 74 | if(value != null) 75 | { 76 | value.DrawBackground = true; 77 | value.OpaqueBackground = true; 78 | value.Parent = this; 79 | value.Visible = true; 80 | } 81 | } 82 | } 83 | 84 | public int ItemHeigth 85 | { 86 | get { return itemHeight; } 87 | set 88 | { 89 | if(itemHeight == value) return; 90 | itemHeight = value; 91 | QueueResize (); 92 | } 93 | } 94 | 95 | public Gdk.Size MenuSize 96 | { 97 | get { return menuSize; } 98 | set 99 | { 100 | if(menuSize == value) return; 101 | menuSize = value; 102 | QueueResize (); 103 | } 104 | } 105 | 106 | public Widget DefaultMenu 107 | { 108 | get { return defaultMenu; } 109 | set 110 | { 111 | if(defaultMenu == value) return; 112 | bool updateActive = defaultMenu == activeMenu; 113 | if(updateActive && defaultMenu != null) defaultMenu.Unparent (); 114 | defaultMenu = value; 115 | if(updateActive) SetActiveMenu (value); 116 | } 117 | } 118 | 119 | /// Returns the number of children. 120 | public int NChildren 121 | { 122 | get { return items.Count; } 123 | } 124 | 125 | /// Default constructor. 126 | internal ApplicationMenu (ApplicationButton Button) 127 | { 128 | this.SetFlag (WidgetFlags.NoWindow); 129 | 130 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 131 | 132 | //this.children = new List (); 133 | 134 | //Append (new Button ("OK")); 135 | 136 | appBtn = Button; 137 | items = new List (); 138 | itemHeight = 32; 139 | menuSize = new Gdk.Size (240, 320); 140 | } 141 | 142 | public void Prepend (ApplicationMenuItem i) 143 | { 144 | Insert (i, 0); 145 | } 146 | 147 | public void Append (ApplicationMenuItem i) 148 | { 149 | Insert (i, -1); 150 | } 151 | 152 | public void Insert (ApplicationMenuItem i, int ItemIndex) 153 | { 154 | i.Parent = this; 155 | i.Visible = true; 156 | 157 | if(ItemIndex == -1) 158 | items.Add (i); 159 | else 160 | items.Insert (ItemIndex, i); 161 | } 162 | 163 | public void Remove (int ItemIndex) 164 | { 165 | if(ItemIndex == -1) ItemIndex = items.Count - 1; 166 | 167 | items[ItemIndex].Unparent (); 168 | items.RemoveAt (ItemIndex); 169 | } 170 | 171 | public void ActivateMenu (Widget w) 172 | { 173 | if(w == null) w = defaultMenu; 174 | SetActiveMenu (w); 175 | } 176 | 177 | private void SetActiveMenu (Widget w) 178 | { 179 | if(activeMenu != null) activeMenu.Unparent (); 180 | activeMenu = w; 181 | w.Parent = this; 182 | w.Visible = true; 183 | QueueResize (); 184 | } 185 | 186 | public void ShowAt (int x, int y) 187 | { 188 | //if(win != null) KillMenu (true); 189 | 190 | //foreach(ApplicationMenuItem item in items) item.Parent = this; 191 | 192 | if(win == null) 193 | { 194 | win = new SyntheticWindow (WindowType.Popup); 195 | win.Child = this; 196 | 197 | win.Hidden += delegate { KillMenu (true); }; 198 | 199 | win.ShowAll (); 200 | win.GdkWindow.Move (x, y - verticalWindowOffset); 201 | 202 | win.ButtonPressEvent += delegate { KillMenu (true); }; 203 | win.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 204 | } 205 | else 206 | { 207 | win.ShowAll (); 208 | win.GdkWindow.Move (x, y - verticalWindowOffset); 209 | } 210 | 211 | Grab.Add (win); 212 | Gdk.GrabStatus grabbed = Gdk.Pointer.Grab (win.GdkWindow, true, Gdk.EventMask.ButtonPressMask, null, null, 0); 213 | if(grabbed != Gdk.GrabStatus.Success) 214 | { 215 | KillMenu (false); 216 | return; 217 | } 218 | 219 | grabbed = Gdk.Keyboard.Grab (win.GdkWindow, true, 0); 220 | if(grabbed != Gdk.GrabStatus.Success) 221 | { 222 | KillMenu (false); 223 | return; 224 | } 225 | } 226 | 227 | private void KillMenu (bool Ungrab) 228 | { 229 | if(this.win == null) return; 230 | 231 | //Window win = this.win; 232 | //this.win = null; 233 | 234 | //win.Child = null; 235 | 236 | Grab.Remove (win); 237 | if(Ungrab) 238 | { 239 | Gdk.Pointer.Ungrab (0); 240 | Gdk.Keyboard.Ungrab (0); 241 | } 242 | win.Hide (); 243 | this.Hide (); 244 | //win.Destroy (); 245 | } 246 | 247 | protected override void ForAll (bool include_internals, Callback callback) 248 | { 249 | foreach(Widget w in items) 250 | { 251 | if(w.Visible) callback (w); 252 | } 253 | 254 | if(optionsBtn != null && optionsBtn.Visible) 255 | { 256 | callback (optionsBtn); 257 | } 258 | 259 | if(exitBtn != null && exitBtn.Visible) 260 | { 261 | callback (exitBtn); 262 | } 263 | 264 | if(activeMenu != null && activeMenu.Visible) 265 | { 266 | callback (activeMenu); 267 | } 268 | } 269 | 270 | protected override void OnSizeRequested (ref Requisition requisition) 271 | { 272 | base.OnSizeRequested (ref requisition); 273 | 274 | menuItemsColWidth = 0; 275 | int menuItemsColHeight = 0; 276 | 277 | foreach(ApplicationMenuItem mi in items) 278 | { 279 | if(mi.Visible) 280 | { 281 | mi.HeightRequest = itemHeight; 282 | Gtk.Requisition req = mi.SizeRequest (); 283 | if(req.Width > menuItemsColWidth) menuItemsColWidth = req.Width; 284 | menuItemsColHeight += itemHeight; 285 | } 286 | } 287 | 288 | requisition.Height = menuItemsColHeight; 289 | requisition.Width = menuItemsColWidth; 290 | 291 | if(activeMenu != null) 292 | { 293 | /*Gtk.Requisition req = activeMenu.SizeRequest (); 294 | requisition.Width += req.Width; 295 | if(req.Height > requisition.Height) requisition.Height = req.Height;*/ 296 | 297 | requisition.Width += menuSize.Width; 298 | if(menuSize.Height > requisition.Height) requisition.Height = menuSize.Height; 299 | } 300 | 301 | int buttonsWidth = 0; 302 | buttonsHeight = 0; 303 | 304 | if(optionsBtn != null) 305 | { 306 | Gtk.Requisition req = optionsBtn.SizeRequest (); 307 | buttonsWidth = req.Width; 308 | buttonsHeight = req.Height; 309 | optionsBtnWidth = req.Width; 310 | } 311 | 312 | if(exitBtn != null) 313 | { 314 | Gtk.Requisition req = exitBtn.SizeRequest (); 315 | buttonsWidth += req.Width; 316 | if(optionsBtn != null) buttonsWidth += space; 317 | if(req.Height > buttonsHeight) buttonsHeight = req.Height; 318 | exitBtnWidth = req.Width; 319 | } 320 | 321 | if(buttonsWidth > requisition.Width) requisition.Width = buttonsWidth; 322 | 323 | if(buttonsHeight > 0) requisition.Height += buttonsHeight + space; 324 | requisition.Width += borderWidth << 1; 325 | requisition.Height += borderWidth + topPadding; 326 | 327 | this.menuItemsColWidth = menuItemsColWidth; 328 | } 329 | 330 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 331 | { 332 | base.OnSizeAllocated (allocation); 333 | 334 | visibleMenuItems = 0; 335 | exitBtnVisible = optionsBtnVisible = false; 336 | 337 | allocation.Height -= borderWidth; 338 | 339 | if(buttonsHeight + topPadding <= allocation.Height) 340 | { 341 | Gdk.Rectangle alloc; 342 | 343 | if(buttonsHeight > 0) 344 | { 345 | alloc.X = allocation.Right - borderWidth; 346 | alloc.Y = allocation.Bottom - buttonsHeight; 347 | alloc.Height = buttonsHeight; 348 | 349 | if(exitBtn != null) 350 | { 351 | alloc.X -= exitBtnWidth; 352 | alloc.Width = exitBtnWidth; 353 | if(alloc.X >= allocation.X + borderWidth) 354 | { 355 | exitBtn.SizeAllocate (alloc); 356 | } 357 | } 358 | 359 | if(optionsBtn != null) 360 | { 361 | if(exitBtn != null) alloc.X -= space; 362 | alloc.X -= optionsBtnWidth; 363 | alloc.Width = optionsBtnWidth; 364 | if(alloc.X >= allocation.X + borderWidth) 365 | { 366 | optionsBtn.SizeAllocate (alloc); 367 | } 368 | } 369 | 370 | allocation.Height -= buttonsHeight + space; 371 | } 372 | 373 | alloc.X = allocation.X + borderWidth; 374 | alloc.Y = allocation.Y + topPadding; 375 | itemsAlloc.X = alloc.X; 376 | itemsAlloc.Y = alloc.Y; 377 | alloc.Height = itemHeight; 378 | if(allocation.Right - alloc.X - borderWidth < menuItemsColWidth) 379 | { 380 | menuItemsColWidth = allocation.Right - alloc.X - borderWidth; 381 | } 382 | 383 | if(menuItemsColWidth > 0) 384 | { 385 | alloc.Width = menuItemsColWidth; 386 | 387 | foreach(ApplicationMenuItem mi in items) 388 | { 389 | if(mi.Visible) 390 | { 391 | if(alloc.Bottom <= allocation.Bottom) 392 | { 393 | mi.SizeAllocate (alloc); 394 | alloc.Y += itemHeight; 395 | ++visibleMenuItems; 396 | } 397 | } 398 | } 399 | } 400 | 401 | itemsAlloc.Width = menuItemsColWidth + space; 402 | itemsAlloc.Height = allocation.Bottom - itemsAlloc.Y - borderWidth; 403 | 404 | if(activeMenu != null) 405 | { 406 | alloc.X = allocation.X + borderWidth + menuItemsColWidth + space; 407 | alloc.Width = allocation.Right - alloc.X - borderWidth; 408 | alloc.Y = allocation.Y + topPadding; 409 | alloc.Height = allocation.Bottom - alloc.Y - borderWidth; 410 | 411 | if(alloc.Width > 0 && alloc.Width > 0) 412 | { 413 | activeMenu.SizeAllocate (alloc); 414 | } 415 | } 416 | } 417 | } 418 | 419 | protected override bool OnButtonPressEvent (Gdk.EventButton evnt) 420 | { 421 | SetActiveMenu (defaultMenu); 422 | return base.OnButtonPressEvent (evnt); 423 | } 424 | 425 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 426 | { 427 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 428 | 429 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 430 | cr.Clip (); 431 | Draw (cr); 432 | 433 | ((IDisposable)cr.Target).Dispose (); 434 | ((IDisposable)cr).Dispose (); 435 | 436 | return base.OnExposeEvent (evnt); 437 | } 438 | 439 | protected void Draw (Context cr) 440 | { 441 | Rectangle rect = new Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 442 | theme.DrawApplicationMenu (cr, rect, itemsAlloc, lineWidth, this); 443 | } 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /Ribbons/ApplicationMenuItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using Gtk; 4 | using Cairo; 5 | 6 | namespace Ribbons 7 | { 8 | /// 9 | /// Single item to be displayed in the application menu. 10 | /// 11 | public class ApplicationMenuItem : Bin 12 | { 13 | private static readonly TimeSpan openTimeoutSec = new TimeSpan (0, 0, 0, 0, 300); 14 | private const double lineWidth = 1.0; 15 | private const double arrowPadding = 2.0; 16 | private const double arrowSize = 10.0; 17 | private const double roundSize = 3.0; 18 | 19 | private Theme.MenuItemState state = Theme.MenuItemState.Default; 20 | private bool menuOpened = false; 21 | private int padding = 2; 22 | private Gdk.Rectangle arrowAllocation; 23 | private double effectiveArrowSize; 24 | 25 | private Timer timer; 26 | 27 | private Widget img; 28 | private Label lbl; 29 | private Widget menu; 30 | 31 | protected Theme theme = Theme.DefaultTheme; 32 | 33 | [GLib.Signal("action")] 34 | public event EventHandler Action; 35 | 36 | /// Image to display. 37 | public Widget Image 38 | { 39 | set 40 | { 41 | if(img == value) return; 42 | if(img != null) UnbindWidget (img); 43 | img = value; 44 | if(img != null) BindWidget (img); 45 | UpdateImageLabel (); 46 | } 47 | get { return img; } 48 | } 49 | 50 | /// Label to display. 51 | public string Label 52 | { 53 | set 54 | { 55 | if(lbl != null) UnbindWidget (lbl); 56 | lbl = new Gtk.Label (value); 57 | lbl.Xalign = 0; 58 | if(lbl != null) BindWidget (lbl); 59 | UpdateImageLabel (); 60 | } 61 | get 62 | { 63 | return lbl == null ? null : lbl.Text; 64 | } 65 | } 66 | 67 | public Widget Menu 68 | { 69 | get { return menu; } 70 | set 71 | { 72 | menu = value; 73 | QueueResize (); 74 | } 75 | } 76 | 77 | /// Default constructor. 78 | public ApplicationMenuItem () 79 | { 80 | this.SetFlag (WidgetFlags.NoWindow); 81 | 82 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 83 | 84 | this.timer = new Timer (OpenMenuNow); 85 | } 86 | 87 | /// Constructor given a label to display. 88 | /// Label to display. 89 | public ApplicationMenuItem (string Label) : this () 90 | { 91 | this.Label = Label; 92 | } 93 | 94 | /// Constructor given an image to display. 95 | /// Image to display 96 | public ApplicationMenuItem (Image Image) : this () 97 | { 98 | this.Image = Image; 99 | } 100 | 101 | /// Constructor given a label and an image to display. 102 | /// Image to display. 103 | /// Label to display. 104 | public ApplicationMenuItem (Image Image, string Label) : this () 105 | { 106 | this.Image = Image; 107 | this.Label = Label; 108 | } 109 | 110 | /// Constructs a Button from a stock. 111 | /// Name of the stock. 112 | /// true if the image should be large, false otherwise. 113 | public static ApplicationMenuItem FromStockIcon (string Name, bool Large) 114 | { 115 | Image img = new Image (Name, Large ? IconSize.LargeToolbar : IconSize.SmallToolbar); 116 | return new ApplicationMenuItem (img); 117 | } 118 | 119 | /// Constructs a Button from a stock. 120 | /// Name of the stock. 121 | /// Label to display. 122 | /// true if the image should be large, false otherwise. 123 | public static ApplicationMenuItem FromStockIcon (string Name, string Label, bool Large) 124 | { 125 | Image img = new Image (Name, Large ? IconSize.LargeToolbar : IconSize.SmallToolbar); 126 | return new ApplicationMenuItem (img, Label); 127 | } 128 | 129 | public override void Dispose () 130 | { 131 | base.Dispose (); 132 | timer.Dispose (); 133 | } 134 | 135 | /// Fires the Action event. 136 | public void Click () 137 | { 138 | if(Action != null) Action (this, EventArgs.Empty); 139 | } 140 | 141 | private void OpenMenuNow (object State) 142 | { 143 | ApplicationMenu win = Parent as ApplicationMenu; 144 | win.ActivateMenu (menu); 145 | } 146 | 147 | /// Updates the child widget containing the label and/or image. 148 | protected void UpdateImageLabel () 149 | { 150 | if(Child != null) 151 | { 152 | Container con = Child as Container; 153 | if(con != null) 154 | { 155 | con.Remove (img); 156 | con.Remove (lbl); 157 | } 158 | Remove (Child); 159 | } 160 | 161 | if(lbl != null && img != null) 162 | { 163 | HBox box = new HBox (false, 0); 164 | box.Add (img); 165 | box.Add (lbl); 166 | Child = box; 167 | } 168 | else if(lbl != null) 169 | { 170 | Child = lbl; 171 | } 172 | else if(img != null) 173 | { 174 | Child = img; 175 | } 176 | } 177 | 178 | /// Binds a widget to listen to all button events. 179 | protected void BindWidget (Widget w) 180 | { 181 | w.ButtonPressEvent += BindedWidget_ButtonPressEvent; 182 | w.ButtonReleaseEvent += BindedWidget_ButtonReleaseEvent; 183 | } 184 | 185 | /// Unbinds a widget to no longer listen to button events. 186 | protected void UnbindWidget (Widget w) 187 | { 188 | w.ButtonPressEvent -= BindedWidget_ButtonPressEvent; 189 | w.ButtonReleaseEvent -= BindedWidget_ButtonReleaseEvent; 190 | } 191 | 192 | protected void BindedWidget_ButtonPressEvent (object sender, ButtonPressEventArgs evnt) 193 | { 194 | ProcessEvent (evnt.Event); 195 | } 196 | 197 | protected void BindedWidget_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs evnt) 198 | { 199 | ProcessEvent (evnt.Event); 200 | Click (); 201 | } 202 | 203 | protected override void OnSizeRequested (ref Requisition requisition) 204 | { 205 | base.OnSizeRequested (ref requisition); 206 | 207 | Requisition childRequisition = new Requisition (); 208 | if(Child != null) 209 | { 210 | childRequisition = Child.SizeRequest (); 211 | } 212 | 213 | if(Menu != null) 214 | { 215 | int arrowSpace = (int)(arrowSize + 2 * (lineWidth + arrowPadding)); 216 | childRequisition.Width += arrowSpace; 217 | } 218 | 219 | if(HeightRequest == -1) 220 | { 221 | requisition.Height = childRequisition.Height + (int)(lineWidth * 4 + padding * 2); 222 | } 223 | if(WidthRequest == -1) 224 | { 225 | requisition.Width = childRequisition.Width + (int)(lineWidth * 4 + padding * 2); 226 | } 227 | } 228 | 229 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 230 | { 231 | base.OnSizeAllocated (allocation); 232 | 233 | effectiveArrowSize = arrowSize; 234 | 235 | if(Menu != null) 236 | { 237 | if(Action != null) 238 | arrowAllocation.Width = (int)(arrowSize + 2 * arrowPadding); 239 | else 240 | arrowAllocation.Width = (int)(allocation.Width - 4 * lineWidth); 241 | 242 | arrowAllocation.Height = (int)(allocation.Height - 4 * lineWidth); 243 | 244 | arrowAllocation.X = (int)(allocation.Right - arrowAllocation.Width - 2 * lineWidth); 245 | arrowAllocation.Y = (int)(allocation.Bottom - arrowAllocation.Height - 2 * lineWidth); 246 | } 247 | else 248 | { 249 | effectiveArrowSize = 0; 250 | } 251 | 252 | allocation.X += (int)(lineWidth * 2 + padding); 253 | allocation.Y += (int)(lineWidth * 2 + padding); 254 | allocation.Height -= (int)(lineWidth * 4 + padding * 2); 255 | allocation.Width -= (int)(lineWidth * 4 + padding * 2); 256 | 257 | if(Menu != null) 258 | { 259 | int arrowSpace = (int)(effectiveArrowSize + 2 * (lineWidth + arrowPadding)); 260 | allocation.Width -= arrowSpace; 261 | } 262 | 263 | if(allocation.Height < 0) allocation.Height = 0; 264 | if(allocation.Width < 0) allocation.Width = 0; 265 | 266 | if(Child != null) 267 | { 268 | Child.SizeAllocate (allocation); 269 | } 270 | } 271 | 272 | protected override bool OnMotionNotifyEvent (Gdk.EventMotion evnt) 273 | { 274 | bool ret = base.OnMotionNotifyEvent (evnt); 275 | UpdateState ((int)evnt.X, (int)evnt.Y); 276 | return ret; 277 | } 278 | 279 | protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt) 280 | { 281 | bool ret = base.OnEnterNotifyEvent (evnt); 282 | menuOpened = false; 283 | UpdateState ((int)evnt.X, (int)evnt.Y); 284 | return ret; 285 | } 286 | 287 | private void UpdateState (int x, int y) 288 | { 289 | Theme.MenuItemState newState; 290 | 291 | if(Menu != null && Action != null && arrowAllocation.Contains (x, y)) 292 | { 293 | newState = Theme.MenuItemState.HilightMenu; 294 | } 295 | else if(menuOpened || Action == null) 296 | { 297 | newState = Theme.MenuItemState.Hilight; 298 | } 299 | else 300 | { 301 | newState = Theme.MenuItemState.HilightAction; 302 | } 303 | 304 | if(state != newState) 305 | { 306 | if(newState == Theme.MenuItemState.Hilight || newState == Theme.MenuItemState.HilightMenu) 307 | timer.Change (openTimeoutSec, new TimeSpan (-1)); 308 | else 309 | timer.Change (-1, -1); 310 | 311 | state = newState; 312 | this.QueueDraw (); 313 | } 314 | } 315 | 316 | protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt) 317 | { 318 | timer.Change (-1, -1); 319 | 320 | bool ret = base.OnLeaveNotifyEvent (evnt); 321 | state = Theme.MenuItemState.Default; 322 | this.QueueDraw (); 323 | return ret; 324 | } 325 | 326 | protected override bool OnButtonPressEvent (Gdk.EventButton evnt) 327 | { 328 | bool ret = base.OnButtonPressEvent (evnt); 329 | 330 | /*if(Menu != null && arrowAllocation.Contains ((int)evnt.X, (int)evnt.Y)) 331 | { 332 | ActivateMenu (); 333 | }*/ 334 | 335 | return ret; 336 | } 337 | 338 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 339 | { 340 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 341 | 342 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 343 | cr.Clip (); 344 | Draw (cr); 345 | 346 | ((IDisposable)cr.Target).Dispose (); 347 | ((IDisposable)cr).Dispose (); 348 | 349 | return base.OnExposeEvent (evnt); 350 | } 351 | 352 | protected void Draw (Context cr) 353 | { 354 | Rectangle rect = new Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 355 | bool drawSeparator = Action != null && Menu != null; 356 | theme.DrawApplicationMenuItem (cr, rect, state, roundSize, lineWidth, effectiveArrowSize, arrowPadding, drawSeparator, this); 357 | } 358 | } 359 | } 360 | -------------------------------------------------------------------------------- /Ribbons/BaseButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// Foundation of all buttons. 8 | public abstract class BaseButton : Bin 9 | { 10 | protected Theme theme = Theme.DefaultTheme; 11 | protected GroupStyle groupStyle; 12 | protected Theme.ButtonState state = Theme.ButtonState.Default; 13 | protected PositionType imgPos; 14 | protected bool drawBg, opaqueBg; 15 | protected Widget img; 16 | protected Label lbl; 17 | protected double padding; 18 | protected bool isSmall; 19 | protected bool enable; 20 | 21 | /// Spacing between the content and the widget. 22 | public double Padding 23 | { 24 | set 25 | { 26 | if(padding == value) return; 27 | padding = value; 28 | QueueDraw (); 29 | } 30 | get { return padding; } 31 | } 32 | 33 | /// Shape of the widget. 34 | public GroupStyle GroupStyle 35 | { 36 | set { groupStyle = value; } 37 | get { return groupStyle; } 38 | } 39 | 40 | /// true if the widget should paint a background, false otherwise. 41 | public bool DrawBackground 42 | { 43 | set 44 | { 45 | if(drawBg == value) return; 46 | drawBg = value; 47 | QueueDraw (); 48 | } 49 | get { return drawBg; } 50 | } 51 | 52 | public bool OpaqueBackground 53 | { 54 | set 55 | { 56 | if(opaqueBg == value) return; 57 | opaqueBg = value; 58 | QueueDraw (); 59 | } 60 | get { return opaqueBg; } 61 | } 62 | 63 | /// true if the button is enabled, false otherwise. 64 | public bool Enabled 65 | { 66 | set 67 | { 68 | if(enable == value) return; 69 | enable = value; 70 | QueueDraw (); 71 | } 72 | get { return enable; } 73 | } 74 | 75 | /// Image to display. 76 | public Widget Image 77 | { 78 | set 79 | { 80 | if(img == value) return; 81 | if(img != null) UnbindWidget (img); 82 | img = value; 83 | if(img != null) BindWidget (img); 84 | UpdateImageLabel (); 85 | } 86 | get { return img; } 87 | } 88 | 89 | /// Position of the image relative to the label. 90 | public PositionType ImagePosition 91 | { 92 | set 93 | { 94 | if(imgPos == value) return; 95 | imgPos = value; 96 | UpdateImageLabel (); 97 | } 98 | get { return imgPos; } 99 | } 100 | 101 | /// Label to display. 102 | public string Label 103 | { 104 | set 105 | { 106 | if(lbl != null) UnbindWidget (lbl); 107 | lbl = new Gtk.Label (value); 108 | if(lbl != null) BindWidget (lbl); 109 | UpdateImageLabel (); 110 | } 111 | get 112 | { 113 | return lbl == null ? null : lbl.Text; 114 | } 115 | } 116 | 117 | /// Theme used to draw the widget. 118 | public Theme Theme 119 | { 120 | set 121 | { 122 | theme = value; 123 | QueueDraw (); 124 | } 125 | get { return theme; } 126 | } 127 | 128 | /// Binds a widget to listen to all button events. 129 | protected void BindWidget (Widget w) 130 | { 131 | w.ButtonPressEvent += BindedWidget_ButtonPressEvent; 132 | w.ButtonReleaseEvent += BindedWidget_ButtonReleaseEvent; 133 | } 134 | 135 | /// Unbinds a widget to no longer listen to button events. 136 | protected void UnbindWidget (Widget w) 137 | { 138 | w.ButtonPressEvent -= BindedWidget_ButtonPressEvent; 139 | w.ButtonReleaseEvent -= BindedWidget_ButtonReleaseEvent; 140 | } 141 | 142 | /// Called when a mouse button has been pressed on a binded widget. 143 | protected abstract void BindedWidget_ButtonPressEvent (object sender, ButtonPressEventArgs evnt); 144 | 145 | /// Called when a mouse button has been release on a binded widget. 146 | protected abstract void BindedWidget_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs evnt); 147 | 148 | /// Updates the child widget containing the label and/or image. 149 | protected void UpdateImageLabel () 150 | { 151 | if(Child != null) 152 | { 153 | Container con = Child as Container; 154 | if(con != null) 155 | { 156 | con.Remove (img); 157 | con.Remove (lbl); 158 | } 159 | Remove (Child); 160 | } 161 | 162 | if(lbl != null && img != null) 163 | { 164 | switch(imgPos) 165 | { 166 | case PositionType.Top: 167 | { 168 | VBox box = new VBox (false, 0); 169 | box.Add (img); 170 | box.Add (lbl); 171 | Child = box; 172 | break; 173 | } 174 | case PositionType.Bottom: 175 | { 176 | VBox box = new VBox (false, 0); 177 | box.Add (lbl); 178 | box.Add (img); 179 | Child = box; 180 | break; 181 | } 182 | case PositionType.Left: 183 | { 184 | HBox box = new HBox (false, 0); 185 | box.Add (img); 186 | box.Add (lbl); 187 | Child = box; 188 | break; 189 | } 190 | case PositionType.Right: 191 | { 192 | HBox box = new HBox (false, 0); 193 | box.Add (lbl); 194 | box.Add (img); 195 | Child = box; 196 | break; 197 | } 198 | } 199 | } 200 | else if(lbl != null) 201 | { 202 | Child = lbl; 203 | } 204 | else if(img != null) 205 | { 206 | Child = img; 207 | } 208 | } 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /Ribbons/Button.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// Button to be used in Ribbons. 8 | public class Button : BaseButton 9 | { 10 | private Menu dropDownMenu; 11 | 12 | private double arrowSize; 13 | private Gdk.Rectangle arrowAllocation; 14 | 15 | protected const double lineWidth = 1.0; 16 | protected const double arrowPadding = 2.0; 17 | protected const double smallArrowSize = 5.0; 18 | protected const double bigArrowSize = 8.0; 19 | 20 | /// Fired when the button is clicked. 21 | [GLib.Signal("clicked")] 22 | public event EventHandler Clicked; 23 | 24 | /// Drop down menu displayed when the arrow is pressed. 25 | public Menu DropDownMenu 26 | { 27 | set 28 | { 29 | dropDownMenu = value; 30 | QueueDraw (); 31 | } 32 | get 33 | { 34 | return dropDownMenu; 35 | } 36 | } 37 | 38 | /// Default constructor. 39 | public Button () 40 | { 41 | this.SetFlag (WidgetFlags.NoWindow); 42 | 43 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 44 | 45 | this.Padding = 2; 46 | this.ImagePosition = PositionType.Top; 47 | this.isSmall = false; 48 | this.enable = true; 49 | } 50 | 51 | /// Constructor given a label to display. 52 | /// Label to display. 53 | public Button (string Label) : this () 54 | { 55 | this.Label = Label; 56 | } 57 | 58 | /// Constructor given an image to display. 59 | /// Image to display 60 | public Button (Image Image) : this () 61 | { 62 | this.Image = Image; 63 | } 64 | 65 | /// Constructor given a label and an image to display. 66 | /// Image to display. 67 | /// Label to display. 68 | public Button (Image Image, string Label) : this () 69 | { 70 | this.Image = Image; 71 | this.Label = Label; 72 | } 73 | 74 | /// Constructs a Button from a stock. 75 | /// Name of the stock. 76 | /// true if the image should be large, false otherwise. 77 | public static Button FromStockIcon (string Name, bool Large) 78 | { 79 | Image img = new Image (Name, Large ? IconSize.LargeToolbar : IconSize.SmallToolbar); 80 | Button btn = new Button (img); 81 | if(!Large) btn.ImagePosition = PositionType.Left; 82 | return btn; 83 | } 84 | 85 | /// Constructs a Button from a stock. 86 | /// Name of the stock. 87 | /// Label to display. 88 | /// true if the image should be large, false otherwise. 89 | public static Button FromStockIcon (string Name, string Label, bool Large) 90 | { 91 | Image img = new Image (Name, Large ? IconSize.LargeToolbar : IconSize.SmallToolbar); 92 | Button btn = new Button (img, Label); 93 | if(!Large) btn.ImagePosition = PositionType.Left; 94 | return btn; 95 | } 96 | 97 | /// Fires the Click event. 98 | public virtual void Click () 99 | { 100 | if(enable && Clicked != null) Clicked (this, EventArgs.Empty); 101 | } 102 | 103 | /// Displays the drop down menu if any. 104 | public void Popup () 105 | { 106 | if(enable && dropDownMenu != null) 107 | { 108 | dropDownMenu.Popup (); 109 | dropDownMenu.ShowAll (); 110 | } 111 | } 112 | 113 | protected override void BindedWidget_ButtonPressEvent (object sender, ButtonPressEventArgs evnt) 114 | { 115 | ProcessEvent (evnt.Event); 116 | } 117 | 118 | protected override void BindedWidget_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs evnt) 119 | { 120 | ProcessEvent (evnt.Event); 121 | Click (); 122 | } 123 | 124 | protected override void OnSizeRequested (ref Requisition requisition) 125 | { 126 | base.OnSizeRequested (ref requisition); 127 | 128 | Requisition childRequisition = new Requisition (); 129 | if(Child != null && Child.Visible) 130 | { 131 | childRequisition = Child.SizeRequest (); 132 | } 133 | 134 | if(dropDownMenu != null) 135 | { 136 | int arrowSpace = (int)((isSmall ? smallArrowSize : bigArrowSize) + 2 * (lineWidth + arrowPadding)); 137 | 138 | if(imgPos == PositionType.Top || imgPos == PositionType.Bottom) 139 | { 140 | childRequisition.Height += arrowSpace; 141 | } 142 | else 143 | { 144 | childRequisition.Width += arrowSpace; 145 | } 146 | } 147 | 148 | if(HeightRequest == -1) 149 | { 150 | requisition.Height = childRequisition.Height + (int)(lineWidth * 4 + padding * 2); 151 | } 152 | if(WidthRequest == -1) 153 | { 154 | requisition.Width = childRequisition.Width + (int)(lineWidth * 4 + padding * 2); 155 | } 156 | } 157 | 158 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 159 | { 160 | base.OnSizeAllocated (allocation); 161 | 162 | if(dropDownMenu != null) 163 | { 164 | arrowSize = isSmall ? smallArrowSize : bigArrowSize; 165 | 166 | if(imgPos == PositionType.Top || imgPos == PositionType.Bottom) 167 | { 168 | if(Clicked != null) 169 | arrowAllocation.Height = (int)(arrowSize + 2 * arrowPadding); 170 | else 171 | arrowAllocation.Height = (int)(allocation.Height - 4 * lineWidth); 172 | 173 | arrowAllocation.Width = (int)(allocation.Width - 4 * lineWidth); 174 | } 175 | else 176 | { 177 | if(Clicked != null) 178 | arrowAllocation.Width = (int)(arrowSize + 2 * arrowPadding); 179 | else 180 | arrowAllocation.Width = (int)(allocation.Width - 4 * lineWidth); 181 | 182 | arrowAllocation.Height = (int)(allocation.Height - 4 * lineWidth); 183 | } 184 | 185 | arrowAllocation.X = (int)(allocation.Right - arrowAllocation.Width - 2 * lineWidth); 186 | arrowAllocation.Y = (int)(allocation.Bottom - arrowAllocation.Height - 2 * lineWidth); 187 | } 188 | else 189 | { 190 | arrowSize = 0; 191 | } 192 | 193 | allocation.X += (int)(lineWidth * 2 + padding); 194 | allocation.Y += (int)(lineWidth * 2 + padding); 195 | allocation.Height -= (int)(lineWidth * 4 + padding * 2); 196 | allocation.Width -= (int)(lineWidth * 4 + padding * 2); 197 | 198 | if(dropDownMenu != null) 199 | { 200 | int arrowSpace = (int)((isSmall ? smallArrowSize : bigArrowSize) + 2 * (lineWidth + arrowPadding)); 201 | 202 | if(imgPos == PositionType.Top || imgPos == PositionType.Bottom) 203 | { 204 | allocation.Height -= arrowSpace; 205 | } 206 | else 207 | { 208 | allocation.Width -= arrowSpace; 209 | } 210 | } 211 | 212 | if(allocation.Height < 0) allocation.Height = 0; 213 | if(allocation.Width < 0) allocation.Width = 0; 214 | 215 | if(Child != null && Child.Visible) 216 | { 217 | Child.SizeAllocate (allocation); 218 | } 219 | } 220 | 221 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 222 | { 223 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 224 | 225 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 226 | cr.Clip (); 227 | Draw (cr); 228 | 229 | ((IDisposable)cr.Target).Dispose (); 230 | ((IDisposable)cr).Dispose (); 231 | 232 | return base.OnExposeEvent (evnt); 233 | } 234 | 235 | protected void Draw (Context cr) 236 | { 237 | Rectangle rect = new Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 238 | double roundSize = isSmall ? 2.0 : 3.0; 239 | bool drawSeparator = (Clicked != null) && (dropDownMenu != null); 240 | theme.DrawButton (cr, rect, state, roundSize, lineWidth, arrowSize, arrowPadding, drawSeparator, this); 241 | } 242 | 243 | protected override bool OnButtonPressEvent (Gdk.EventButton evnt) 244 | { 245 | bool ret = base.OnButtonPressEvent (evnt); 246 | state = Theme.ButtonState.Pressed; 247 | if(!enable) state = Theme.ButtonState.Default; 248 | this.QueueDraw (); 249 | 250 | if(dropDownMenu != null && arrowAllocation.Contains ((int)evnt.X, (int)evnt.Y)) 251 | { 252 | Popup (); 253 | } 254 | 255 | return ret; 256 | } 257 | 258 | protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt) 259 | { 260 | bool ret = base.OnButtonReleaseEvent (evnt); 261 | state = Theme.ButtonState.Hover; 262 | if(!enable) state = Theme.ButtonState.Default; 263 | this.QueueDraw (); 264 | return ret; 265 | } 266 | 267 | protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt) 268 | { 269 | bool ret = base.OnEnterNotifyEvent (evnt); 270 | state = Theme.ButtonState.Hover; 271 | if(!enable) state = Theme.ButtonState.Default; 272 | this.QueueDraw (); 273 | return ret; 274 | } 275 | 276 | protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt) 277 | { 278 | bool ret = base.OnLeaveNotifyEvent (evnt); 279 | state = Theme.ButtonState.Default; 280 | this.QueueDraw (); 281 | return ret; 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /Ribbons/ChangeLog: -------------------------------------------------------------------------------- 1 | 2008-08-26 Laurent Debacker 2 | 3 | * QuickAccessToolbar.cs, Gallery.cs, Theme.cs, ApplicationMenuItem.cs, 4 | Ribbon.cs, RibbonGroup.cs, ApplicationMenu.cs, BaseButton.cs: Use the 5 | Default Theme instead of creating a new instance for each widget. 6 | 7 | 2008-08-18 Laurent Debacker 8 | 9 | * QuickAccessToolbar.cs, Ribbon.cs: Add support for key tips. 10 | * VariantsCombinaisonSwitcher.cs, ApplicationMenuItem.cs, 11 | VariantsCombinaison.cs, ApplicationMenu.cs, DropdownRibbonGroup.cs: Add 12 | summary. 13 | * Gallery.cs: Add support for multi selection. 14 | * Theme.cs: Update theme for key tips. 15 | * SyntheticWindow.cs: Remove debug code. 16 | * KeyTip.cs: Initial commit of KeyTip. 17 | * ApplicationButton.cs: Support for key tips. 18 | 19 | 2008-08-15 Laurent Debacker 20 | 21 | 22 | 23 | 2008-08-11 Laurent Debacker 24 | 25 | * Button.cs: Make Click method virtual 26 | * ToggleButton.cs: Allow toggle buttons to display an arrow 27 | * VariantsCombinaisonSwitcher.cs: Introduction of variants combinaisons 28 | switcher. 29 | * ToolBox.cs: Bugfix for size requests 30 | * VariantsCombinaison.cs: Bugfix for size requests, and hierachy 31 | * Ribbon.cs: Revert to previous version of Ribbon (I have opted for another 32 | solution for variants combinaisons) 33 | * DropdownRibbonGroup.cs: Introduction of Drop down ribbon group 34 | 35 | 2008-08-05 Laurent Debacker 36 | 37 | * GroupVariant.cs: Implementation of the concept of "variant" for Group. 38 | * VariantsCombinaison.cs: Implementation for the concept of variant 39 | combinaisons. 40 | * Ribbon.cs: Migrating Ribbon to variants combinaisons. 41 | 42 | 2008-07-24 Laurent Debacker 43 | 44 | * Theme.cs: Enhanced key tip theme 45 | * SyntheticWindow.cs: Debug code 46 | * RibbonGroup.cs: Avoid memory leak 47 | 48 | 2008-07-18 Laurent Debacker 49 | 50 | * ApplicationMenuItem.cs: Open/close menu on mouse hover, with timer 51 | * ApplicationMenu.cs: Reset default menu on button click 52 | 53 | 2008-07-17 Laurent Debacker 54 | 55 | * ApplicationMenu.cs: hide container when windows is hidden 56 | * ApplicationButton.cs: keep the app menu pressed while the app menu is 57 | opened 58 | 59 | 2008-07-14 Laurent Debacker 60 | 61 | * ApplicationMenuItem.cs: Text align fix, and delayed menu opening. 62 | * ApplicationMenu.cs: One hard-coded value removed 63 | 64 | 2008-07-11 Laurent Debacker 65 | 66 | * Theme.cs: More compliant app menu background, and new feature for buttons: 67 | opaque background. 68 | * ApplicationMenu.cs: Opaque buttons, window offset. 69 | * ApplicationButton.cs: API update 70 | * BaseButton.cs: New feature: opaque background 71 | 72 | 2008-07-11 Laurent Debacker 73 | 74 | * Theme.cs: Nicer menu items background 75 | * ApplicationMenuItem.cs: Attempt to fix justification of menu item labels, 76 | not ok yet 77 | * ApplicationMenu.cs: Fixed menu size 78 | 79 | 2008-07-11 Laurent Debacker 80 | 81 | * ApplicationMenu.cs: Working menu opening 82 | 83 | 2008-07-11 Laurent Debacker 84 | 85 | * Theme.cs: First steps for the app menu theme 86 | * ApplicationMenuItem.cs: Better handling of fast moving pointers 87 | * ApplicationMenu.cs: Bugfixes 88 | 89 | 2008-07-11 Laurent Debacker 90 | 91 | * Theme.cs: Better behavior of hilighs for app menu item 92 | * ApplicationMenuItem.cs: More work on proper app menu item behavior 93 | (hilights) 94 | 95 | 2008-07-10 Laurent Debacker 96 | 97 | * Theme.cs: Fix them code for app menu item 98 | * ApplicationMenuItem.cs: Bug fixes 99 | * ApplicationMenu.cs: Remove debug code 100 | 101 | 2008-07-09 Laurent Debacker 102 | 103 | * ApplicationMenu.cs: Bugfix, can now open app menu multiple times 104 | 105 | 2008-07-08 Laurent Debacker 106 | 107 | * QuickAccessToolbar.cs, FlowLayoutContainer.cs: Bugfix in remove 108 | * Theme.cs, ApplicationMenuItem.cs: API update 109 | * ApplicationMenu.cs: Lot of work to solve the rendering bug. It is now 110 | gone, but I cannot open the menu more than once... 111 | 112 | 2008-07-07 Laurent Debacker 113 | 114 | * Theme.cs: Initial theme code for app menu item borowed from button 115 | * ApplicationMenuItem.cs: Size alloc, size request, drawing 116 | * ApplicationMenu.cs: Bug fix in size alloc 117 | 118 | 2008-07-07 Laurent Debacker 119 | 120 | * ApplicationMenu.cs: Autohide the app menu when required 121 | 122 | 2008-07-07 Laurent Debacker 123 | 124 | * Theme.cs: Updated for new app menu API 125 | * ApplicationMenuItem.cs, ApplicationMenu.cs: Major refactoring 126 | * ApplicationButton.cs: Update for new App menu API 127 | 128 | 2008-07-06 Laurent Debacker 129 | 130 | * ApplicationMenu.cs: Compilation bug fixes, sorry 131 | 132 | 2008-07-06 Laurent Debacker 133 | 134 | * Theme.cs: Dummy renderer for App menu and app menu item 135 | * ApplicationMenu.cs: More work on app menu item 136 | 137 | 2008-07-04 Laurent Debacker 138 | 139 | * ApplicationButton.cs: Bugfixes for popup position, and misc other bug 140 | fixes 141 | 142 | 2008-07-04 Laurent Debacker 143 | 144 | * ApplicationMenu.cs: Implementation of SizeAllocated for app menu, and more 145 | work on SizeRequest 146 | 147 | 2008-07-04 Laurent Debacker 148 | 149 | * ApplicationMenu.cs: Size requisition for app menu 150 | 151 | 2008-07-03 Laurent Debacker 152 | 153 | * Theme.cs: Fix background theme for Quick Access Toolbar when there is no 154 | app button 155 | 156 | 2008-06-30 Laurent Debacker 157 | 158 | * Theme.cs: Quick Access Toolbar background 159 | * ApplicationMenu.cs: Initial stub API for application menu. 160 | * QuickAccessToolbar.cs: Take care of height requests from children widgets 161 | 162 | 2008-06-28 Laurent Debacker 163 | 164 | * Theme.cs: Title bar's background is not compliant 165 | * Ribbon.cs: Fix title bar layout code 166 | 167 | 2008-06-28 Laurent Debacker 168 | 169 | * Theme.cs: Implementation of the required drop shadow for the app button 170 | 171 | 2008-06-27 Laurent Debacker 172 | 173 | * Theme.cs: Change background color depending on current state 174 | * Ribbon.cs: Bugfix for layout code 175 | * ApplicationButton.cs: Bugfix for widget initialization 176 | 177 | 2008-06-27 Laurent Debacker 178 | 179 | * QuickAccessToolbar.cs: Bugfix, add NO_WINDOW flag 180 | * Theme.cs: Implement final app button theme 181 | * Ribbon.cs: Bugfix, call app button and quick access toolbar when calling 182 | children 183 | 184 | 2008-06-23 Laurent Debacker 185 | 186 | * QuickAccessToolbar.cs: Implement size request and size allocation. 187 | 188 | 2008-06-16 Laurent Debacker 189 | 190 | * Theme.cs: Stub for the application button. 191 | * Ribbon.cs: Support for the application button. 192 | * ApplicationButton.cs: Initial commit. 193 | 194 | 2008-06-09 Laurent Debacker 195 | 196 | * Ribbon.cs: 197 | 198 | * More work a the layout of the QuickAccessToolbar 199 | 200 | * QuickAccessToolbar.cs: 201 | 202 | * Add minimal code to be able to use it as a child widget in the demo. 203 | 204 | * Theme.cs: 205 | 206 | * Drawing of the QuickAccessToolbar's background. 207 | 208 | 2008-06-02 Laurent Debacker 209 | 210 | * Ribbon.cs: 211 | 212 | * Add new Toolbar property to control the QuickAccessToolbar that 213 | belongs to a Ribbon. 214 | 215 | * Update Size Request 216 | 217 | * Update Allocations 218 | 219 | * Bugfix in the allocation 220 | 221 | * QuickAccessToolbar.cs: 222 | 223 | * Initial commit of the new Quick Access Toolbar widget with bare metal 224 | API. 225 | 226 | * ToolBox.cs: 227 | 228 | * Fixed a typo in a comment. 229 | 230 | 2008-06-02 Laurent Debacker 231 | 232 | * Ribbon.cs: 233 | 234 | * Add new Toolbar property to control the QuickAccessToolbar that 235 | belongs to a Ribbon. 236 | 237 | * Update Size Request 238 | 239 | * Update Allocations 240 | 241 | * Bugfix in the allocation 242 | 243 | * QuickAccessToolbar.cs: 244 | 245 | * Initial commit of the new Quick Access Toolbar widget with bare metal 246 | API. 247 | 248 | * ToolBox.cs: 249 | 250 | * Fixed a typo in a comment. 251 | 252 | 2008-02-07 Laurent Debacker 253 | 254 | * Gallery.cs, GalleryPopupWindow.cs: * You can now click anywhere to close 255 | the popup. (Paweł 'X4lldux' Drygas). 256 | 257 | * Proper tile selection. (Paweł 'X4lldux' Drygas). 258 | 259 | 2008-01-25 Laurent Debacker 260 | 261 | * RibbonGroup.cs, Button.cs: Added signal names to enable accelerators. 262 | 263 | 2008-01-19 Laurent Debacker 264 | 265 | * Theme.cs, Position.cs, RibbonGroup.cs, Ribbons.mdp: Left, Right, and Top 266 | position for the label of RibbonGroup implemented. 267 | 268 | 2007-12-27 Laurent Debacker 269 | 270 | * Ribbon.cs, ToggleButton.cs, RibbonGroup.cs, Tile.cs, Gallery.cs, Theme.cs, 271 | gtk-gui/generated.cs, gtk-gui/objects.xml, gtk-gui/gui.stetic, 272 | Ribbons.mdp, Button.cs, ChangeLog: Fixing calls to Dispose() and 273 | Destroy() 274 | 275 | -------------------------------------------------------------------------------- /Ribbons/ColorScheme.cs: -------------------------------------------------------------------------------- 1 | using Cairo; 2 | using System; 3 | 4 | namespace Ribbons 5 | { 6 | /// Color scheme. 7 | public class ColorScheme 8 | { 9 | private Color prettyDark, dark, lightDark, normal, lightBright, bright, prettyBright; 10 | 11 | public Color PrettyDark 12 | { 13 | set { prettyDark = value; } 14 | get { return prettyDark; } 15 | } 16 | 17 | public Color Dark 18 | { 19 | set { dark = value; } 20 | get { return dark; } 21 | } 22 | 23 | public Color LightDark 24 | { 25 | set { lightDark = value; } 26 | get { return lightDark; } 27 | } 28 | 29 | public Color Normal 30 | { 31 | set { normal = value; } 32 | get { return normal; } 33 | } 34 | 35 | public Color LightBright 36 | { 37 | set { lightBright = value; } 38 | get { return lightBright; } 39 | } 40 | 41 | public Color Bright 42 | { 43 | set { bright = value; } 44 | get { return bright; } 45 | } 46 | 47 | public Color PrettyBright 48 | { 49 | set { prettyBright = value; } 50 | get { return prettyBright; } 51 | } 52 | 53 | //public ColorScheme() : this (new Color(0.957, 0.957, 0.957)) 54 | public ColorScheme() : this (new Color(0.867, 0.867, 0.867)) 55 | //public ColorScheme() : this (new Color(0.925, 0.914, 0.847)) 56 | //public ColorScheme() : this (new Color(0.937, 0.922, 0.898)) 57 | { 58 | 59 | } 60 | 61 | public ColorScheme (Color Normal) 62 | { 63 | prettyDark = GetColorRelative (Normal, -0.4); 64 | dark = GetColorRelative (Normal, -0.1); 65 | lightDark = GetColorRelative (Normal, -0.05); 66 | normal = Normal; 67 | lightBright = GetColorRelative (Normal, 0.05); 68 | bright = GetColorRelative (Normal, 0.1); 69 | prettyBright = GetColorRelative (Normal, 0.15); 70 | } 71 | 72 | internal static Color SetAlphaChannel(Color C, double Alpha) 73 | { 74 | return new Color (C.R, C.G, C.B, Alpha); 75 | } 76 | 77 | internal static Color GetColorAbsolute(Color C, double luminance) 78 | { 79 | /*double h, s, v; 80 | RGB2HSV(C, out h, out s, out v); 81 | v = v + (1.7 * (luminance - 1)); 82 | if(v < 0) v = 0; else if(v > 1) v = 1; 83 | return HSV2RGB(h, s, v);*/ 84 | 85 | double h, s, l; 86 | RGB2HSL(C, out h, out s, out l); 87 | /*double a = (h % 60) / 60; 88 | if(a > 0.5) a -= 0.5;*/ 89 | //l = l + (1.7 * (luminance - 1)); 90 | l = luminance; 91 | if(l < 0) l = 0; else if(l > 1) l = 1; 92 | return HSL2RGB(h, s, l); 93 | } 94 | 95 | internal static Color GetColorRelative(Color C, double luminance) 96 | { 97 | double h, s, l; 98 | RGB2HSL(C, out h, out s, out l); 99 | /*double a = (h % 60) / 60; 100 | if(a > 0.5) a -= 0.5;*/ 101 | l = l + luminance; 102 | if(l < 0) l = 0; else if(l > 1) l = 1; 103 | return HSL2RGB(h, s, l); 104 | } 105 | 106 | private static void RGB2HSL(Color C, out double H, out double S, out double L) 107 | { 108 | double r = C.R, g = C.G, b = C.B; 109 | double max = Math.Max(r, Math.Max(g, b)); 110 | double min = Math.Min(r, Math.Min(g, b)); 111 | L = 0.5 * (max + min); 112 | if(max == min) 113 | { 114 | H = double.NaN; 115 | } 116 | else 117 | { 118 | if(max == r) 119 | { 120 | if(g >= b) 121 | H = (g-b)/(max-min) * 60; 122 | else 123 | H = (g-b)/(max-min) * 60 + 360; 124 | } 125 | else if(max == g) 126 | H = (b-r)/(max-min) * 60 + 120; 127 | else 128 | H = (r-g)/(max-min) * 60 + 240; 129 | } 130 | if(0.0000001 <= L && L <= 0.5) 131 | S = (max-min) / (2*L); 132 | else if(L > 0.5) 133 | S = (max-min) / (2-2*L); 134 | else 135 | S = 0; 136 | } 137 | 138 | private static Color HSL2RGB(double H, double S, double L) 139 | { 140 | double r = L, g = L, b = L; 141 | double Q; 142 | if(L < 0.5) 143 | Q = L * (1 + S); 144 | else 145 | Q = L + S - L * S; 146 | double P = 2 * L - Q; 147 | if(Q > 0) 148 | { 149 | double m = L + L - Q; 150 | H /= 60; 151 | int i = (int)H % 6; 152 | double vsf = Q * (Q - m) / Q * (H - i); 153 | switch(i) 154 | { 155 | case 0: 156 | r = Q; 157 | g = m + vsf; 158 | b = m; 159 | break; 160 | case 1: 161 | r = m - vsf; 162 | g = Q; 163 | b = m; 164 | break; 165 | case 2: 166 | r = m; 167 | g = Q; 168 | b = m + vsf; 169 | break; 170 | case 3: 171 | r = m; 172 | g = m - vsf; 173 | b = Q; 174 | break; 175 | case 4: 176 | r = m + vsf; 177 | g = m; 178 | b = Q; 179 | break; 180 | case 5: 181 | r = Q; 182 | g = m; 183 | b = m - vsf; 184 | break; 185 | } 186 | } 187 | return new Color (r, g, b); 188 | } 189 | 190 | private static void RGB2HSV(Color C, out double H, out double S, out double V) 191 | { // http://www.daniweb.com/techtalkforums/thread38302.html 192 | double r = C.R, g = C.G, b = C.B; 193 | double max = Math.Max (r, Math.Max (g, b)); 194 | double min = Math.Min (r, Math.Min (g, b)); 195 | double delta = max - min; 196 | V = max; 197 | if(Math.Abs (delta) < 0.0000001) 198 | { 199 | H = S = 0; 200 | } 201 | else 202 | { 203 | S = delta / max; 204 | if(r == max) 205 | H = 60.0 * (g - b) / delta; 206 | else if(g == max) 207 | H = 60.0 * (2 + (b - r) / delta); 208 | else 209 | H = 60.0 * (4 + (r - g) / delta); 210 | if(H < 0) H += 360; else if(H > 360) H -= 360; 211 | } 212 | } 213 | 214 | private static Color HSV2RGB(double H, double S, double V) 215 | { // http://en.wikipedia.org/wiki/HSV_color_space 216 | int H_i = (int)(H / 60) % 6; 217 | double f = H / 60 - H_i; 218 | if(H_i == 0) return new Color (V, V * (1 - (1 - f) * S), V * (1 - S)); 219 | if(H_i == 1) return new Color (V * (1 - f * S), V, V * (1 - S)); 220 | if(H_i == 2) return new Color (V * (1 - S), V, V * (1 - (1 - f) * S)); 221 | if(H_i == 3) return new Color (V * (1 - S), V * (1 - f * S), V); 222 | if(H_i == 4) return new Color (V * (1 - (1 - f) * S), V * (1 - S), V); 223 | return new Color (V, V * (1 - S), V * (1 - f * S)); 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /Ribbons/DropdownRibbonGroup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Gtk; 3 | 4 | namespace Ribbons 5 | { 6 | /// 7 | /// A toggle button replacing a ribbon group when space is too constrained. 8 | /// 9 | public class DropdownRibbonGroup : ToggleButton 10 | { 11 | private RibbonGroup group; 12 | private SyntheticWindow win; 13 | 14 | public RibbonGroup Group 15 | { 16 | get { return group; } 17 | set { group = value; } 18 | } 19 | 20 | public DropdownRibbonGroup () 21 | { 22 | DrawBackground = true; 23 | ImagePosition = PositionType.Top; 24 | isSmall = false; 25 | DisplayArrow = true; 26 | } 27 | 28 | protected override void BindedWidget_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs evnt) 29 | { 30 | base.BindedWidget_ButtonReleaseEvent (sender, evnt); 31 | 32 | if(Value) 33 | { 34 | int x, y; 35 | ParentWindow.GetOrigin (out x, out y); 36 | x += Allocation.X; 37 | y += Allocation.Bottom; 38 | 39 | ShowAt (x, y); 40 | } 41 | else 42 | { 43 | KillMenu (true); 44 | } 45 | } 46 | 47 | private void ShowAt (int x, int y) 48 | { 49 | if(win != null) return; 50 | 51 | win = new SyntheticWindow (WindowType.Popup); 52 | win.Child = group; 53 | 54 | win.Hidden += delegate { KillMenu (true); }; 55 | 56 | win.ShowAll (); 57 | win.GdkWindow.Move (x, y); 58 | 59 | win.ButtonReleaseEvent += delegate { KillMenu (true); }; 60 | win.AddEvents ((int)(Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 61 | 62 | Grab.Add (win); 63 | Gdk.GrabStatus grabbed = Gdk.Pointer.Grab (win.GdkWindow, true, Gdk.EventMask.ButtonPressMask, null, null, 0); 64 | if(grabbed != Gdk.GrabStatus.Success) 65 | { 66 | KillMenu (false); 67 | return; 68 | } 69 | 70 | grabbed = Gdk.Keyboard.Grab (win.GdkWindow, true, 0); 71 | if(grabbed != Gdk.GrabStatus.Success) 72 | { 73 | KillMenu (false); 74 | return; 75 | } 76 | } 77 | 78 | private void KillMenu (bool Ungrab) 79 | { 80 | if(win == null) return; 81 | 82 | Grab.Remove (win); 83 | if(Ungrab) 84 | { 85 | Gdk.Pointer.Ungrab (0); 86 | Gdk.Keyboard.Ungrab (0); 87 | } 88 | win.Hide (); 89 | group.Unparent (); 90 | win = null; 91 | 92 | Value = false; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Ribbons/ExtraEventBox.cs: -------------------------------------------------------------------------------- 1 | using Gtk; 2 | using System; 3 | 4 | namespace Ribbons 5 | { 6 | /// EventBox extended to transmit all events. 7 | public class ExtraEventBox : EventBox 8 | { 9 | protected override bool OnWidgetEvent (Gdk.Event evnt) 10 | { 11 | if(evnt.Window.Equals (this.GdkWindow)) 12 | { 13 | if(evnt.Type != Gdk.EventType.Expose) 14 | { 15 | if(Child != null) Child.ProcessEvent (evnt); 16 | } 17 | } 18 | return base.OnWidgetEvent (evnt); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Ribbons/FlowLayoutContainer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// Container displaying children using a flow layout. 8 | public class FlowLayoutContainer : Container 9 | { 10 | private List children; 11 | private Requisition[] childReqs; 12 | 13 | /// Returns the number of children. 14 | public int NChildren 15 | { 16 | get { return children.Count; } 17 | } 18 | 19 | /// Default constructor. 20 | public FlowLayoutContainer() 21 | { 22 | this.SetFlag (WidgetFlags.NoWindow); 23 | 24 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 25 | 26 | this.children = new List (); 27 | } 28 | 29 | /// Adds a widget before all existing widgetw. 30 | /// The widget to add. 31 | public void Prepend (Widget w) 32 | { 33 | Insert (w, 0); 34 | } 35 | 36 | /// Adds a widget after all existing widgets. 37 | /// The widget to add. 38 | public void Append (Widget w) 39 | { 40 | Insert (w, -1); 41 | } 42 | 43 | /// Inserts a widget at the specified location. 44 | /// The widget to add. 45 | /// The index (starting at 0) at which the widget must be inserted, or -1 to insert the widget after all existing widgets. 46 | public void Insert (Widget w, int WidgetIndex) 47 | { 48 | w.Parent = this; 49 | w.Visible = true; 50 | 51 | if(WidgetIndex == -1) 52 | children.Add (w); 53 | else 54 | children.Insert (WidgetIndex, w); 55 | 56 | ShowAll (); 57 | } 58 | 59 | /// Removes the widget at the specified index. 60 | /// Index of the widget to remove. 61 | public void Remove (int WidgetIndex) 62 | { 63 | if(WidgetIndex == -1) WidgetIndex = children.Count - 1; 64 | 65 | children[WidgetIndex].Parent = null; 66 | children.RemoveAt (WidgetIndex); 67 | 68 | ShowAll (); 69 | } 70 | 71 | protected override void ForAll (bool include_internals, Callback callback) 72 | { 73 | foreach(Widget w in children) 74 | { 75 | if(w.Visible) callback (w); 76 | } 77 | } 78 | 79 | protected override void OnSizeRequested (ref Requisition requisition) 80 | { 81 | base.OnSizeRequested (ref requisition); 82 | 83 | int n = children.Count, nVisible = 0; 84 | childReqs = new Requisition[n]; 85 | for(int i = 0 ; i < n ; ++i) 86 | { 87 | if(children[i].Visible) 88 | { 89 | childReqs[i] = children[i].SizeRequest (); 90 | ++nVisible; 91 | } 92 | } 93 | 94 | if(WidthRequest != -1) 95 | { 96 | if(HeightRequest == -1) 97 | { 98 | int currentLineHeight = 0, currentLineWidth = 0; 99 | foreach(Widget w in children) 100 | { 101 | if(w.Visible) 102 | { 103 | Requisition childReq = w.SizeRequest (); 104 | currentLineHeight = Math.Max (childReq.Height, currentLineHeight); 105 | currentLineWidth += childReq.Width; 106 | if(currentLineWidth >= WidthRequest) 107 | { 108 | currentLineHeight = 0; 109 | currentLineWidth = 0; 110 | } 111 | } 112 | } 113 | requisition.Height = currentLineHeight; 114 | } 115 | } 116 | else // (WidthRequest == -1) 117 | { 118 | if(HeightRequest == -1) 119 | { 120 | foreach(Widget w in children) 121 | { 122 | if(w.Visible) 123 | { 124 | Requisition childReq = w.SizeRequest (); 125 | requisition.Height = Math.Max (childReq.Height, requisition.Height); 126 | requisition.Width += childReq.Width; 127 | } 128 | } 129 | } 130 | else 131 | { 132 | #if !EXPERIMENTAL 133 | int totalWidth = 0, maxWidth = 0; 134 | for(int i = 0 ; i < n ; ++i) 135 | { 136 | if(children[i].Visible) 137 | { 138 | totalWidth += childReqs[i].Width; 139 | maxWidth = Math.Max (childReqs[i].Width, maxWidth); 140 | } 141 | } 142 | 143 | // TODO: the following algorithm a dichotomic-like search approach (lower bound: 1, upper bound: number of widgets) 144 | 145 | int lineCount = 0; 146 | int totalHeight = 0; 147 | 148 | do 149 | { 150 | ++lineCount; 151 | int lineWidth = (int)Math.Ceiling ((double)totalWidth / lineCount); 152 | if(lineWidth < maxWidth) break; 153 | int currentLineWidth = 0, currentLineHeight = 0; 154 | for(int i = 0 ; i < n ; ++i) 155 | { 156 | if(children[i].Visible) 157 | { 158 | currentLineWidth += childReqs[i].Width; 159 | if(currentLineWidth > lineWidth) 160 | { 161 | totalHeight += currentLineHeight; 162 | currentLineWidth = childReqs[i].Width; 163 | currentLineHeight = 0; 164 | } 165 | currentLineHeight = Math.Max (childReqs[i].Height, currentLineHeight); 166 | } 167 | } 168 | totalHeight += currentLineHeight; 169 | 170 | if(totalHeight <= HeightRequest) 171 | { 172 | requisition.Width = lineWidth; 173 | } 174 | } while(totalHeight < HeightRequest && lineCount < nVisible); 175 | #else 176 | int height = 0; 177 | for(int i = 0 ; i < n ; ++i) 178 | { 179 | height = Math.Max (childReqs[i].Height, height); 180 | } 181 | 182 | List segments = new List(); 183 | segments.Add (0); 184 | segments.Add (n); 185 | 186 | for(;;) 187 | { 188 | int bestCandidateHeight = int.MaxValue; 189 | int bestSplit = -1; 190 | for(int i = 1 ; i < segments.Count ; ++i) 191 | { 192 | int oldSum, newSum; 193 | int splitPos = SplitWidgetsInTwo (childReqs, segments[i-1], segments[i] - 1, out oldSum, out newSum); 194 | int candidate = height - oldSum + newSum; 195 | if(newSum < oldSum && candidate < bestCandidateHeight) 196 | { 197 | bestSplit = splitPos; 198 | bestCandidateHeight = candidate; 199 | } 200 | } 201 | 202 | if(bestCandidateHeight < HeightRequest) 203 | { 204 | segments.Insert (~segments.BinarySearch (bestSplit), bestSplit); 205 | } 206 | else break; 207 | } 208 | 209 | int currentSegmentWidth = 0, currentSegmentNr = 1; 210 | for(int i = 0 ; i < n ; ++i) 211 | { 212 | if(i == segments[currentSegmentNr]) 213 | { 214 | ++currentSegmentNr; 215 | WidthRequest = Math.Max (currentSegmentNr, WidthRequest); 216 | currentSegmentNr = 0; 217 | } 218 | currentSegmentWidth += childReqs[i].Width; 219 | } 220 | requisition.Width = Math.Max (currentSegmentNr, WidthRequest); 221 | #endif 222 | } 223 | } 224 | } 225 | 226 | #if EXPERIMENTAL 227 | private int SplitWidgetsInTwo (Requisition[] Requisitions, int Index, int Length, out int PreviousSum, out int NewSum) 228 | { 229 | int[] maxLeft = new int[Length], maxRight = new int[Length]; 230 | maxLeft[0] = Requisitions[Index].Width; 231 | maxRight[Length-1] = Requisitions[Index+Length-1].Width; 232 | PreviousSum = 0; 233 | for(int i = 1 ; i < Length ; ++i) 234 | { 235 | maxLeft[i] = Math.Max (maxLeft[i-1] , Requisitions[i+Index].Width); 236 | maxRight[Length-1-i] = Math.Max (maxLeft[Length-i] , Requisitions[Length-1-i+Index].Width); 237 | PreviousSum += Requisitions[i+Index].Height; 238 | } 239 | 240 | int ret = 0, smallestSum = int.MaxValue; 241 | for(int i = 0 ; i < Length ; ++i) 242 | { 243 | int sum = maxLeft[i] + maxRight[i]; 244 | if(sum < smallestSum) 245 | { 246 | smallestSum = sum; 247 | ret = i + Index + 1; 248 | } 249 | } 250 | 251 | NewSum = smallestSum; 252 | return ret; 253 | } 254 | #endif 255 | 256 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 257 | { 258 | base.OnSizeAllocated (allocation); 259 | 260 | int n = children.Count; 261 | Gdk.Rectangle childAlloc = allocation; 262 | int lineHeight = 0; 263 | for(int i = 0 ; i < n ; ++i) 264 | { 265 | if(children[i].Visible) 266 | { 267 | childAlloc.Width = childReqs[i].Width; 268 | childAlloc.Height = childReqs[i].Height; 269 | 270 | if(childAlloc.X != allocation.X && childAlloc.Right > allocation.Right) 271 | { 272 | childAlloc.X = allocation.X; 273 | childAlloc.Y += lineHeight; 274 | lineHeight = 0; 275 | } 276 | 277 | children[i].SizeAllocate (childAlloc); 278 | childAlloc.X += childAlloc.Width; 279 | lineHeight = Math.Max (childAlloc.Height, lineHeight); 280 | } 281 | } 282 | } 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /Ribbons/Gallery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Cairo; 4 | using Gtk; 5 | 6 | namespace Ribbons 7 | { 8 | /// Gallery of Tiles. 9 | public class Gallery : Container 10 | { 11 | protected Theme theme = Theme.DefaultTheme; 12 | private int tileWidth, tileHeight; 13 | private List tiles; 14 | private Button up, down; 15 | private ToggleButton expand; 16 | private int defaultTilesPerRow; 17 | private int tileSpacing; 18 | private GalleryPopupWindow popup; 19 | 20 | private bool multiSelect; 21 | private List selectedTiles; 22 | private int firstDisplayedTileIndex, lastDisplayedTileIndex; 23 | private int btnWidth; 24 | private Requisition upReq, downReq, expandReq; 25 | private Gdk.Rectangle tilesAlloc; 26 | 27 | private const double space = 2.0; 28 | private const double lineWidth = 1.0; 29 | 30 | /// Fired when a Tile has been selected. 31 | public event TileSelectedHandler TileSelected; 32 | 33 | /// Gets or sets the width of Tiles. 34 | public int TileWidth 35 | { 36 | set 37 | { 38 | tileWidth = value; 39 | QueueDraw (); 40 | } 41 | get { return tileWidth; } 42 | } 43 | 44 | /// Gets or sets the height of Tiles. 45 | public int TileHeight 46 | { 47 | set 48 | { 49 | tileHeight = value; 50 | QueueDraw (); 51 | } 52 | get { return tileHeight; } 53 | } 54 | 55 | /// Gets or sets the spacing between Tiles. 56 | public int TileSpacing 57 | { 58 | set 59 | { 60 | tileSpacing = value; 61 | QueueDraw (); 62 | } 63 | get { return tileSpacing; } 64 | } 65 | 66 | /// Gets or sets the default number of Tiles per row. 67 | public int DefaultTilesPerRow 68 | { 69 | set 70 | { 71 | defaultTilesPerRow = value; 72 | QueueDraw (); 73 | } 74 | get { return defaultTilesPerRow; } 75 | } 76 | 77 | /// Gets or sets the selected Tile. 78 | public Tile SelectedTile 79 | { 80 | set 81 | { 82 | if(popup != null) 83 | { 84 | Grab.Remove(popup); 85 | Gdk.Pointer.Ungrab(0); 86 | Gdk.Keyboard.Ungrab(0); 87 | 88 | popup.Hide (); 89 | popup.Destroy(); 90 | popup = null; 91 | } 92 | 93 | if(selectedTiles.Count > 0) 94 | { 95 | foreach(Tile t in selectedTiles) t.Selected = false; 96 | } 97 | selectedTiles.Clear (); 98 | selectedTiles.Add (value); 99 | if(value != null) 100 | { 101 | value.Selected = true; 102 | 103 | int idx = tiles.FindIndex (delegate (Tile t) { return t == value; }); 104 | if(idx != -1) 105 | { 106 | firstDisplayedTileIndex = idx/defaultTilesPerRow*defaultTilesPerRow; 107 | lastDisplayedTileIndex = -1; 108 | UpdateTilesLayout (); 109 | QueueDraw (); 110 | } 111 | } 112 | } 113 | get { return selectedTiles.Count == 0 ? null : selectedTiles[selectedTiles.Count-1]; } 114 | } 115 | 116 | /// Gets the list of selected Tiles. 117 | public IList SelectedTiles 118 | { 119 | get { return selectedTiles.AsReadOnly (); } 120 | } 121 | 122 | /// Returns all Tiles. 123 | public IEnumerable Tiles 124 | { 125 | get 126 | { 127 | return tiles; 128 | } 129 | } 130 | 131 | /// Theme used to draw the widget. 132 | public Theme Theme 133 | { 134 | set 135 | { 136 | theme = value; 137 | QueueDraw (); 138 | } 139 | get { return theme; } 140 | } 141 | 142 | /// Default constructor. 143 | public Gallery() 144 | { 145 | this.SetFlag (WidgetFlags.NoWindow); 146 | 147 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 148 | 149 | this.tiles = new List (); 150 | this.selectedTiles = new List (); 151 | 152 | this.defaultTilesPerRow = 3; 153 | this.firstDisplayedTileIndex = 0; 154 | this.lastDisplayedTileIndex = -1; 155 | this.multiSelect = false; 156 | 157 | this.tileHeight = 56; 158 | this.tileWidth = 72; 159 | this.tileSpacing = 0; 160 | this.BorderWidth = 2; 161 | 162 | this.up = new Button ("\u25B2"); 163 | this.up.Parent = this; 164 | this.up.Padding = 0; 165 | this.up.Clicked += up_Clicked; 166 | 167 | this.down = new Button ("\u25BC"); 168 | this.down.Parent = this; 169 | this.down.Padding = 0; 170 | this.down.Clicked += down_Clicked; 171 | 172 | this.expand = new ToggleButton ("\u2193"); 173 | this.expand.Parent = this; 174 | this.expand.Padding = 0; 175 | this.expand.ValueChanged += expand_ValueChanged; 176 | } 177 | 178 | /// Adds a tile before all existing tiles. 179 | /// The tile to add. 180 | public void PrependTile (Tile t) 181 | { 182 | InsertTile (t, 0); 183 | } 184 | 185 | /// Adds a tile after all existing tiles. 186 | /// The tile to add. 187 | public void AppendTile (Tile t) 188 | { 189 | InsertTile (t, -1); 190 | } 191 | 192 | /// Inserts a tile at the specified location. 193 | /// The tile to add. 194 | /// The index (starting at 0) at which the tile must be inserted, or -1 to insert the tile after all existing tiles. 195 | public void InsertTile (Tile t, int TileIndex) 196 | { 197 | if(TileIndex == -1 || TileIndex == tiles.Count) 198 | { 199 | tiles.Add (t); 200 | } 201 | else 202 | { 203 | tiles.Insert (TileIndex, t); 204 | } 205 | 206 | if (tiles.Count == 1) 207 | SelectedTile = t; 208 | 209 | //t.Parent = this; 210 | t.Visible = true; 211 | t.Clicked += Tile_Clicked; 212 | } 213 | 214 | /// Removes the tile at the specified index. 215 | /// Index of the tile to remove. 216 | public void RemoveTile (int TileIndex) 217 | { 218 | Tile t = tiles[TileIndex]; 219 | t.Clicked -= Tile_Clicked; 220 | t.Unparent (); 221 | if(selectedTiles.Contains (t)) selectedTiles.Remove (t); 222 | 223 | tiles.RemoveAt (TileIndex); 224 | } 225 | 226 | private void up_Clicked(object Sender, EventArgs e) 227 | { 228 | MoveUp (); 229 | } 230 | 231 | private void down_Clicked(object Sender, EventArgs e) 232 | { 233 | MoveDown (); 234 | } 235 | 236 | private void expand_ValueChanged(object Sender, EventArgs e) 237 | { 238 | if(expand.Value) 239 | { 240 | popup = new GalleryPopupWindow (this); 241 | popup.Realized += delegate { 242 | int x, y; 243 | ParentWindow.GetOrigin (out x, out y); 244 | x += Allocation.X; 245 | y += Allocation.Y; 246 | popup.GdkWindow.Move (x, y); 247 | }; 248 | 249 | popup.Hidden += delegate { 250 | expand.ValueChanged -= expand_ValueChanged; 251 | expand.Value = false; 252 | expand.QueueDraw (); 253 | expand.ValueChanged += expand_ValueChanged; 254 | }; 255 | popup.Show (); 256 | 257 | popup.ButtonReleaseEvent += OnButtonReleased; 258 | popup.AddEvents ((int) Gdk.EventMask.ButtonPressMask); 259 | Grab.Add(popup); 260 | 261 | Gdk.GrabStatus grabbed = Gdk.Pointer.Grab(popup.GdkWindow, true, Gdk.EventMask.ButtonReleaseMask, null, null, 0); 262 | if(grabbed == Gdk.GrabStatus.Success) { 263 | grabbed = Gdk.Keyboard.Grab(popup.GdkWindow, true, 0); 264 | 265 | if(grabbed != Gdk.GrabStatus.Success) 266 | { 267 | Grab.Remove(popup); 268 | popup.Hide (); 269 | popup.Destroy(); 270 | popup = null; 271 | 272 | return; 273 | } 274 | } else { 275 | Grab.Remove(popup); 276 | popup.Hide (); 277 | popup.Destroy(); 278 | popup = null; 279 | } 280 | } 281 | else 282 | { 283 | if (popup != null) 284 | { 285 | Grab.Remove(popup); 286 | popup.Hide (); 287 | popup.Destroy(); 288 | popup = null; 289 | } 290 | } 291 | } 292 | 293 | private void Tile_Clicked(object Sender, EventArgs e) 294 | { 295 | Tile selectedTile = (Tile)Sender; 296 | 297 | if(multiSelect) 298 | { 299 | selectedTile.Selected = !selectedTile.Selected; 300 | if(selectedTile.Selected) 301 | selectedTiles.Add (selectedTile); 302 | else 303 | selectedTiles.Remove (selectedTile); 304 | } 305 | else if(Sender != SelectedTile) 306 | { 307 | SelectedTile = selectedTile; 308 | } 309 | 310 | OnTileSelected (selectedTile); 311 | } 312 | 313 | private void MoveUp () 314 | { 315 | if(firstDisplayedTileIndex > 0) 316 | { 317 | firstDisplayedTileIndex = -1; 318 | lastDisplayedTileIndex = firstDisplayedTileIndex - 1; 319 | } 320 | UpdateTilesLayout (); 321 | QueueDraw (); 322 | } 323 | 324 | private void MoveDown () 325 | { 326 | if(lastDisplayedTileIndex < tiles.Count - 1) 327 | { 328 | firstDisplayedTileIndex = lastDisplayedTileIndex + 1; 329 | lastDisplayedTileIndex = -1; 330 | } 331 | UpdateTilesLayout (); 332 | QueueDraw (); 333 | } 334 | 335 | /// Fires the SelectedTile event. 336 | /// The Tile that has been selected. 337 | protected void OnTileSelected (Tile SelectedTile) 338 | { 339 | if(TileSelected != null) TileSelected (this, new TileSelectedEventArgs (SelectedTile)); 340 | } 341 | 342 | private void OnButtonReleased(object o, ButtonReleaseEventArgs args) 343 | { 344 | if(popup != null) { 345 | Grab.Remove(popup); 346 | Gdk.Pointer.Ungrab(0); 347 | Gdk.Keyboard.Ungrab(0); 348 | 349 | popup.Hide (); 350 | popup.Destroy(); 351 | popup = null; 352 | } 353 | } 354 | 355 | private void UpdateTilesLayout () 356 | { 357 | Gdk.Rectangle tileAlloc; 358 | tileAlloc.X = tilesAlloc.X; 359 | tileAlloc.Y = tilesAlloc.Y; 360 | tileAlloc.Height = tilesAlloc.Height; 361 | tileAlloc.Width = tileWidth; 362 | 363 | int maxTiles = (tilesAlloc.Width + tileSpacing) / (tileWidth + tileSpacing); 364 | 365 | if(firstDisplayedTileIndex == -1) 366 | { 367 | firstDisplayedTileIndex = lastDisplayedTileIndex - maxTiles + 1; 368 | if(firstDisplayedTileIndex < 0) 369 | { 370 | lastDisplayedTileIndex -= firstDisplayedTileIndex; 371 | firstDisplayedTileIndex = 0; 372 | } 373 | } 374 | else if(lastDisplayedTileIndex == -1) 375 | { 376 | lastDisplayedTileIndex = firstDisplayedTileIndex + maxTiles - 1; 377 | } 378 | 379 | if(lastDisplayedTileIndex >= tiles.Count) 380 | { 381 | lastDisplayedTileIndex = tiles.Count - 1; 382 | } 383 | 384 | up.Enabled = firstDisplayedTileIndex > 0; 385 | down.Enabled = lastDisplayedTileIndex < tiles.Count - 1; 386 | 387 | for(int tileIndex = 0 ; tileIndex < firstDisplayedTileIndex ; ++tileIndex) 388 | { 389 | if(tiles[tileIndex].Parent != null) tiles[tileIndex].Unparent (); 390 | } 391 | for(int tileIndex = lastDisplayedTileIndex + 1 ; tileIndex < tiles.Count ; ++tileIndex) 392 | { 393 | if(tiles[tileIndex].Parent != null) tiles[tileIndex].Unparent (); 394 | } 395 | 396 | for(int tileIndex = firstDisplayedTileIndex ; tileIndex <= lastDisplayedTileIndex ; ++tileIndex) 397 | { 398 | Tile t = tiles[tileIndex]; 399 | 400 | if(t.Parent == null) t.Parent = this; 401 | 402 | t.SizeRequest (); 403 | 404 | t.SizeAllocate (tileAlloc); 405 | tileAlloc.X += tileAlloc.Width + tileSpacing; 406 | } 407 | } 408 | 409 | protected override void ForAll (bool include_internals, Callback callback) 410 | { 411 | //if(include_internals) 412 | { 413 | callback (up); 414 | callback (down); 415 | callback (expand); 416 | } 417 | 418 | for(int i = firstDisplayedTileIndex ; i <= lastDisplayedTileIndex ; ++i) 419 | { 420 | callback (tiles[i]); 421 | } 422 | } 423 | 424 | protected override void OnSizeRequested (ref Requisition requisition) 425 | { 426 | base.OnSizeRequested (ref requisition); 427 | 428 | upReq = up.SizeRequest (); 429 | downReq = down.SizeRequest (); 430 | expandReq = expand.SizeRequest (); 431 | 432 | btnWidth = Math.Max (upReq.Width, Math.Max (downReq.Width, expandReq.Width)); 433 | int btnHeight = upReq.Height + downReq.Height + expandReq.Height; 434 | 435 | int count = Math.Min (tiles.Count, defaultTilesPerRow); 436 | requisition.Width = btnWidth + (int)space + 2 * (int)lineWidth + count * tileWidth + (count + 1) * tileSpacing + 2 * (int)BorderWidth; 437 | requisition.Height = Math.Max (tileHeight + 2 * (tileSpacing + (int)lineWidth), btnHeight) + 2 * (int)BorderWidth; 438 | 439 | if(WidthRequest != -1) requisition.Width = WidthRequest; 440 | if(HeightRequest != -1) requisition.Height = HeightRequest; 441 | } 442 | 443 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 444 | { 445 | base.OnSizeAllocated (allocation); 446 | 447 | allocation.X += (int)BorderWidth; 448 | allocation.Y += (int)BorderWidth; 449 | allocation.Width -= 2 * (int)BorderWidth; 450 | allocation.Height -= 2 * (int)BorderWidth; 451 | 452 | Gdk.Rectangle btnAlloc; 453 | btnAlloc.Width = btnWidth; 454 | btnAlloc.X = allocation.X + allocation.Width - btnAlloc.Width + 1; 455 | 456 | btnAlloc.Y = allocation.Y; 457 | btnAlloc.Height = upReq.Height; 458 | up.SizeAllocate (btnAlloc); 459 | 460 | btnAlloc.Y += btnAlloc.Height; 461 | btnAlloc.Height = downReq.Height; 462 | down.SizeAllocate (btnAlloc); 463 | 464 | btnAlloc.Y += btnAlloc.Height; 465 | btnAlloc.Height = expandReq.Height; 466 | expand.SizeAllocate (btnAlloc); 467 | 468 | tilesAlloc.X = allocation.X + (int)lineWidth + tileSpacing; 469 | tilesAlloc.Y = allocation.Y + (int)lineWidth + tileSpacing; 470 | tilesAlloc.Width = btnAlloc.X - tilesAlloc.X - tileSpacing - (int)space - 2 * (int)lineWidth; 471 | tilesAlloc.Height = allocation.Height - 2 * (tileSpacing + (int)lineWidth); 472 | 473 | UpdateTilesLayout (); 474 | } 475 | 476 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 477 | { 478 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 479 | 480 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 481 | cr.Clip (); 482 | Draw (cr); 483 | 484 | ((IDisposable)cr.Target).Dispose (); 485 | ((IDisposable)cr).Dispose (); 486 | 487 | return base.OnExposeEvent (evnt); 488 | } 489 | 490 | protected void Draw (Context cr) 491 | { 492 | Rectangle alloc = new Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 493 | Rectangle tiles = new Rectangle (tilesAlloc.X - tileSpacing, tilesAlloc.Y - tileSpacing, tilesAlloc.Width + 2 * tileSpacing, tilesAlloc.Height + 2 * tileSpacing); 494 | theme.DrawGallery (cr, alloc, tiles, this); 495 | } 496 | } 497 | } 498 | -------------------------------------------------------------------------------- /Ribbons/GalleryPopupWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// Popup gallery. 8 | internal class GalleryPopupWindow : Window 9 | { 10 | private const int MAX_HEIGHT = 200; 11 | private const int SCROLLBAR_SIZE = 20; 12 | 13 | private Gallery underlyingGallery; 14 | private List tiles; 15 | private Dictionary mapping; 16 | private uint rows, columns; 17 | private Tile selectedTile; 18 | 19 | private ScrolledWindow internalWindow; 20 | private Table tileTable; 21 | 22 | /// Returns the underlying gallery. 23 | public Gallery UnderlyingGallery 24 | { 25 | get { return underlyingGallery; } 26 | } 27 | 28 | /// Default constructor. 29 | /// The underlying gallery. 30 | public GalleryPopupWindow (Gallery UnderlyingGallery) : base (WindowType.Popup) 31 | { 32 | this.underlyingGallery = UnderlyingGallery; 33 | this.tiles = new List (); 34 | this.mapping = new Dictionary (); 35 | foreach(Tile t in UnderlyingGallery.Tiles) 36 | { 37 | Tile copy = t.Copy (); 38 | copy.Show (); 39 | tiles.Add (copy); 40 | 41 | if(t == UnderlyingGallery.SelectedTile) 42 | { 43 | copy.Selected = true; 44 | selectedTile = t; 45 | } 46 | 47 | mapping.Add (copy, t); 48 | } 49 | 50 | int width = UnderlyingGallery.Allocation.Width; 51 | 52 | columns = (uint)(width / underlyingGallery.TileWidth); 53 | rows = (uint)Math.Ceiling ((double)tiles.Count / columns); 54 | 55 | this.tileTable = new Table (rows, columns, true); 56 | this.tileTable.Show (); 57 | this.tileTable.HeightRequest = (int)rows * UnderlyingGallery.TileHeight; 58 | this.tileTable.WidthRequest = (int)columns * UnderlyingGallery.TileWidth; 59 | 60 | Viewport vp = new Viewport (); 61 | vp.Show (); 62 | vp.Child = tileTable; 63 | 64 | this.internalWindow = new ScrolledWindow (); 65 | this.internalWindow.Show (); 66 | this.internalWindow.Child = vp; 67 | this.internalWindow.HeightRequest = Math.Min (this.tileTable.HeightRequest, MAX_HEIGHT) + SCROLLBAR_SIZE; 68 | this.internalWindow.WidthRequest = this.tileTable.WidthRequest + SCROLLBAR_SIZE; 69 | 70 | uint x = 0, y = 0; 71 | foreach(Tile t in tiles) 72 | { 73 | ExtraEventBox box = new ExtraEventBox (); 74 | box.Show (); 75 | box.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 76 | box.Child = t; 77 | 78 | tileTable.Attach (box, x, x+1, y, y+1); 79 | t.Clicked += tile_Clicked; 80 | 81 | if(++x == columns) 82 | { 83 | x = 0; 84 | ++y; 85 | } 86 | } 87 | 88 | this.Child = internalWindow; 89 | this.Child.ButtonPressEvent += delegate (object o, ButtonPressEventArgs args) { 90 | args.RetVal = true; 91 | }; 92 | } 93 | 94 | private void tile_Clicked (object Sender, EventArgs e) 95 | { 96 | if(selectedTile != null) selectedTile.Selected = false; 97 | selectedTile = (Tile)Sender; 98 | selectedTile.Selected = true; 99 | 100 | underlyingGallery.SelectedTile = mapping[selectedTile]; 101 | 102 | Hide (); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Ribbons/GroupStyle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | /// Position of a widget in a group of widget. 6 | public enum GroupStyle 7 | { 8 | Alone, Left, Center, Right 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Ribbons/GroupVariant.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Gtk; 3 | 4 | namespace Ribbons 5 | { 6 | public class GroupVariant 7 | { 8 | private Widget child; 9 | private int width; 10 | 11 | public Widget Child 12 | { 13 | get { return child; } 14 | } 15 | 16 | public int Width 17 | { 18 | get { return width; } 19 | } 20 | 21 | public GroupVariant (Widget Child) 22 | { 23 | this.child = Child; 24 | this.width = -1; 25 | } 26 | 27 | public void Measure (int Height) 28 | { 29 | child.HeightRequest = Height; 30 | Requisition req = child.SizeRequest (); 31 | width = req.Width; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Ribbons/KeyTip.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Gtk; 3 | 4 | namespace Ribbons 5 | { 6 | public class KeyTip 7 | { 8 | private Widget target; 9 | private string accelerator; 10 | private bool enabled; 11 | private Window win; 12 | private Theme theme = new Theme (); 13 | 14 | public Widget Target 15 | { 16 | get { return target; } 17 | set { target = value; } 18 | } 19 | 20 | public string Accelerator 21 | { 22 | get { return accelerator; } 23 | set { accelerator = value; } 24 | } 25 | 26 | public bool Enabled 27 | { 28 | get { return enabled; } 29 | set { enabled = value; } 30 | } 31 | 32 | public KeyTip () 33 | { 34 | 35 | } 36 | 37 | public KeyTip (Widget Target, string Accelerator) 38 | { 39 | target = Target; 40 | accelerator = Accelerator; 41 | enabled = true; 42 | } 43 | 44 | public void ShowAt (int x, int y, double horizontal_align, double vertical_align) 45 | { 46 | if(win == null) 47 | { 48 | win = new Window (WindowType.Popup); 49 | } 50 | 51 | Pango.Layout layout = win.CreatePangoLayout (accelerator); 52 | int width, height; 53 | layout.GetPixelSize (out width, out height); 54 | width += 2; 55 | height += 2; 56 | 57 | x -= (int)(horizontal_align * width); 58 | y -= (int)(vertical_align * height); 59 | 60 | win.Show (); 61 | win.GdkWindow.Move (x, y); 62 | win.GdkWindow.Resize (width, height); 63 | 64 | win.ExposeEvent += delegate(object Sender, ExposeEventArgs Args) 65 | { 66 | Gdk.EventExpose evnt = Args.Event; 67 | 68 | Cairo.Context cr = Gdk.CairoHelper.Create (win.GdkWindow); 69 | 70 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 71 | cr.Clip (); 72 | theme.DrawKeyTip (cr, new Cairo.Point (win.Allocation.X, win.Allocation.Y), 0, 0, layout); 73 | 74 | ((IDisposable)cr.Target).Dispose (); 75 | ((IDisposable)cr).Dispose (); 76 | }; 77 | } 78 | 79 | public void Hide () 80 | { 81 | if(this.win == null) return; 82 | 83 | win.Hide (); 84 | } 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /Ribbons/PageAddedHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public delegate void PageAddedHandler(object Sender, PageEventArgs Args); 6 | } 7 | -------------------------------------------------------------------------------- /Ribbons/PageEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public class PageEventArgs 6 | { 7 | private Ribbon.RibbonPage page; 8 | 9 | public Ribbon.RibbonPage Page 10 | { 11 | get { return this.page; } 12 | } 13 | 14 | public PageEventArgs (Ribbon.RibbonPage page) 15 | { 16 | this.page = page; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Ribbons/PageMovedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public class PageMovedEventArgs 6 | { 7 | private Ribbon.RibbonPage page; 8 | 9 | public Ribbon.RibbonPage page 10 | { 11 | get { return this.page; } 12 | } 13 | 14 | public PageMovedEventArgs (Ribbon.RibbonPage page) 15 | { 16 | this.page = page; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Ribbons/PageMovedHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public delegate void PageMovedHandler(object Sender, PageEventArgs Args); 6 | } 7 | -------------------------------------------------------------------------------- /Ribbons/PageRemovedHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public delegate void PageRemovedHandler(object Sender, PageEventArgs Args); 6 | } 7 | -------------------------------------------------------------------------------- /Ribbons/PageSelectedHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public delegate void PageSelectedHandler(object Sender, PageEventArgs Args); 6 | } 7 | -------------------------------------------------------------------------------- /Ribbons/Position.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public enum Position 6 | { 7 | Top, Right, Bottom, Left 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Ribbons/QuickAccessToolbar.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gtk; 4 | using Cairo; 5 | 6 | namespace Ribbons 7 | { 8 | /// 9 | /// Displays several widgets (typical shortcuts to common functionalities) next to the application button. 10 | /// 11 | public class QuickAccessToolbar : Container 12 | { 13 | private List widgets; 14 | private List keyTips; 15 | private int[] widths; 16 | private Theme theme = Theme.DefaultTheme; 17 | 18 | public QuickAccessToolbar() 19 | { 20 | // This is a No Window widget => it does not have its own Gdk Window => it can be transparent 21 | this.SetFlag (WidgetFlags.NoWindow); 22 | 23 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 24 | 25 | this.widgets = new List (); 26 | this.keyTips = new List (); 27 | } 28 | 29 | /// Adds a widget before all existing widgets. 30 | /// The widget to add. 31 | public void Prepend (Widget w) 32 | { 33 | Insert (w, 0); 34 | } 35 | 36 | /// Adds a widget after all existing widgets. 37 | /// The widget to add. 38 | public void Append (Widget w) 39 | { 40 | Insert (w, -1); 41 | } 42 | 43 | /// Inserts a widget at the specified location. 44 | /// The widget to add. 45 | /// The index (starting at 0) at which the widget must be inserted, or -1 to insert the widget after all existing widgets. 46 | public void Insert (Widget w, int WidgetIndex) 47 | { 48 | w.Parent = this; 49 | w.Visible = true; 50 | 51 | if(WidgetIndex == -1) 52 | widgets.Add (w); 53 | else 54 | widgets.Insert (WidgetIndex, w); 55 | 56 | ShowAll (); 57 | } 58 | 59 | /// Removes the widget at the specified index. 60 | /// Index of the widget to remove. 61 | public void Remove (int WidgetIndex) 62 | { 63 | if(WidgetIndex == -1) WidgetIndex = widgets.Count - 1; 64 | 65 | widgets[WidgetIndex].Parent = null; 66 | widgets.RemoveAt (WidgetIndex); 67 | 68 | ShowAll (); 69 | } 70 | 71 | public void AddKeyTip (KeyTip kt) 72 | { 73 | keyTips.Add (kt); 74 | } 75 | 76 | public void RemoveKeyTip (KeyTip kt) 77 | { 78 | keyTips.Remove (kt); 79 | } 80 | 81 | public void ClearKeyTips () 82 | { 83 | keyTips.Clear (); 84 | } 85 | 86 | protected override void ForAll (bool include_internals, Callback callback) 87 | { 88 | foreach(Widget w in widgets) 89 | { 90 | if(w.Visible) callback (w); 91 | } 92 | } 93 | 94 | protected override void OnSizeRequested (ref Requisition requisition) 95 | { 96 | base.OnSizeRequested (ref requisition); 97 | 98 | if(widths == null || widths.Length != widgets.Count) 99 | { 100 | widths = new int[widgets.Count]; 101 | } 102 | 103 | requisition.Height = 16; 104 | requisition.Width = 0; 105 | 106 | int i = 0; 107 | foreach(BaseButton b in widgets) 108 | { 109 | //b.HeightRequest = requisition.Height; 110 | Gtk.Requisition req = b.SizeRequest (); 111 | if(req.Height > requisition.Height) requisition.Height = req.Height; 112 | requisition.Width += req.Width; 113 | widths[i++] = req.Width; 114 | } 115 | if(HeightRequest != -1) requisition.Height = HeightRequest; 116 | if(WidthRequest != -1) requisition.Width = WidthRequest; 117 | } 118 | 119 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 120 | { 121 | base.OnSizeAllocated (allocation); 122 | 123 | int i = 0, x = allocation.X; 124 | foreach(BaseButton b in widgets) 125 | { 126 | Gdk.Rectangle r; 127 | r.X = x; 128 | r.Y = allocation.Y; 129 | r.Width = widths[i]; 130 | r.Height = allocation.Height; 131 | b.SizeAllocate (r); 132 | x += r.Width; 133 | ++i; 134 | } 135 | } 136 | 137 | public void ShowKeyTips () 138 | { 139 | int x, y; 140 | GdkWindow.GetOrigin (out x, out y); 141 | int lineY = y + Allocation.Y + (int)(0.66666 * Allocation.Height); 142 | 143 | foreach(KeyTip kt in keyTips) 144 | { 145 | Gdk.Rectangle alloc = kt.Target.Allocation; 146 | kt.ShowAt (x + alloc.X + (alloc.Width >> 1), lineY, 0.5, 0.0); 147 | } 148 | } 149 | 150 | public void HideKeyTips () 151 | { 152 | foreach(KeyTip kt in keyTips) 153 | { 154 | kt.Hide (); 155 | } 156 | } 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /Ribbons/Ribbon.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Cairo; 4 | using Gtk; 5 | 6 | namespace Ribbons 7 | { 8 | /// Ribbon widget. 9 | public class Ribbon : Container 10 | { 11 | private enum KeyTipLevel { None, TopLevel, Tab }; 12 | 13 | private static double borderWidth = 2.0; 14 | private static double space = 2.0; 15 | private static double pagePadding = 3.0; 16 | private static double tabPadding = 4.0; 17 | private static double minimalTabsHorizontalPosition = 8.0; 18 | private static double lineWidth = 1.0; 19 | private static double roundSize = 4.0; 20 | 21 | protected ColorScheme colorScheme = new ColorScheme (); 22 | protected Theme theme = Theme.DefaultTheme; 23 | 24 | protected List pages; 25 | protected int curPageIndex; 26 | protected ApplicationButton appButton; 27 | protected QuickAccessToolbar toolbar; 28 | protected Widget shortcuts; 29 | private Gdk.Rectangle bodyAllocation, pageAllocation; 30 | 31 | private Gtk.Requisition appButtonRequisition; 32 | private Gtk.Requisition toolbarRequisition; 33 | private Gtk.Requisition shortcutsRequisition; 34 | private Gtk.Requisition pageRequisition; 35 | private double headerHeight; 36 | 37 | private KeyTipLevel queuedKeyTipLevel = KeyTipLevel.None; 38 | private List tabKeyTips; 39 | 40 | public event PageSelectedHandler PageSelected; 41 | public event PageAddedHandler PageAdded; 42 | public event PageMovedHandler PageMoved; 43 | public event PageRemovedHandler PageRemoved; 44 | 45 | public ApplicationButton ApplicationButton 46 | { 47 | set 48 | { 49 | if(appButton != null) appButton.Unparent (); 50 | appButton = value; 51 | if(appButton != null) 52 | { 53 | appButton.Visible = true; 54 | appButton.Parent = this; 55 | } 56 | ShowAll (); 57 | } 58 | get 59 | { 60 | return appButton; 61 | } 62 | } 63 | 64 | public QuickAccessToolbar QuickAccessToolbar 65 | { 66 | set 67 | { 68 | if(toolbar != null) toolbar.Unparent (); 69 | toolbar = value; 70 | if(toolbar != null) 71 | { 72 | toolbar.Visible = true; 73 | toolbar.Parent = this; 74 | } 75 | ShowAll (); 76 | } 77 | get 78 | { 79 | return toolbar; 80 | } 81 | } 82 | 83 | /// Indix of the currently selected page. 84 | /// Returns -1 if no page is selected. 85 | public int CurrentPageIndex 86 | { 87 | set 88 | { 89 | if(curPageIndex != -1) 90 | { 91 | CurrentPage.Label.ModifyFg (StateType.Normal, theme.GetForecolorForRibbonTabs (false)); 92 | CurrentPage.Page.Unparent (); 93 | } 94 | curPageIndex = value; 95 | if(curPageIndex != -1) 96 | { 97 | CurrentPage.Label.ModifyFg (StateType.Normal, theme.GetForecolorForRibbonTabs (true)); 98 | CurrentPage.Page.Parent = this; 99 | } 100 | 101 | ShowAll (); 102 | QueueDraw (); 103 | } 104 | get 105 | { 106 | return curPageIndex; 107 | } 108 | } 109 | 110 | /// Currently selected page. 111 | public RibbonPage CurrentPage 112 | { 113 | get 114 | { 115 | int idx = curPageIndex; 116 | return idx == -1 ? null : pages[idx]; 117 | } 118 | } 119 | 120 | /// Number of pages. 121 | public int NPages 122 | { 123 | get { return pages.Count; } 124 | } 125 | 126 | /// Shortcuts widget. 127 | /// The shortcuts widget is displayed next to the tabs. 128 | public Widget Shortcuts 129 | { 130 | set 131 | { 132 | if(shortcuts != null) shortcuts.Unparent (); 133 | shortcuts = value; 134 | if(shortcuts != null) 135 | { 136 | shortcuts.Visible = true; 137 | shortcuts.Parent = this; 138 | } 139 | QueueDraw (); 140 | } 141 | get { return shortcuts; } 142 | } 143 | 144 | /// Theme used to draw the widget. 145 | public Theme Theme 146 | { 147 | set 148 | { 149 | theme = value; 150 | QueueDraw (); 151 | } 152 | get { return theme; } 153 | } 154 | 155 | /// Default constructor. 156 | public Ribbon() 157 | { 158 | this.SetFlag (WidgetFlags.NoWindow); 159 | 160 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 161 | 162 | this.pages = new List (); 163 | this.tabKeyTips = new List (); 164 | this.curPageIndex = -1; 165 | } 166 | 167 | /// Adds a new page after all existing pages. 168 | /// The widget to use as the content of the page. 169 | /// The widget to use as the tab. 170 | public void AppendPage (Widget Child, Widget Label) 171 | { 172 | InsertPage (Child, Label, -1); 173 | } 174 | 175 | /// Adds a new page before all existing pages. 176 | /// The widget to use as the content of the page. 177 | /// The widget to use as the tab. 178 | public void PrependPage (Widget Child, Widget Label) 179 | { 180 | InsertPage (Child, Label, 0); 181 | } 182 | 183 | /// Adds a new page at the specified position. 184 | /// The widget to use as the content of the page. 185 | /// The widget to use as the tab. 186 | /// The index (starting at 0) at which the page must be inserted, or -1 to insert the page after all existing pages. 187 | public void InsertPage (Widget Child, Widget Label, int Position) 188 | { 189 | RibbonPage p = new RibbonPage (this, Child, Label); 190 | 191 | if(Position == -1) 192 | { 193 | pages.Add (p); 194 | } 195 | else 196 | { 197 | pages.Insert (Position, p); 198 | 199 | if(curPageIndex != -1) 200 | { 201 | if(Position <= curPageIndex) 202 | ++curPageIndex; 203 | } 204 | } 205 | 206 | if(pages.Count == 1) 207 | { 208 | CurrentPageIndex = 0; 209 | } 210 | else 211 | { 212 | Label.ModifyFg (StateType.Normal, theme.GetForecolorForRibbonTabs (false)); 213 | } 214 | 215 | Label.ButtonPressEvent += delegate (object sender, ButtonPressEventArgs evnt) 216 | { 217 | this.SelectRibbonPage (p); 218 | }; 219 | 220 | Label.EnterNotifyEvent += delegate (object sender, EnterNotifyEventArgs evnt) 221 | { 222 | 223 | }; 224 | 225 | Label.LeaveNotifyEvent += delegate (object sender, LeaveNotifyEventArgs evnt) 226 | { 227 | 228 | }; 229 | 230 | OnPageAdded (new PageEventArgs (p)); 231 | for(int idx = Position + 1 ; idx < pages.Count ; ++idx) 232 | { 233 | OnPageSelected (new PageEventArgs (pages[idx])); 234 | } 235 | } 236 | 237 | /// Removes the specified page. 238 | /// Index of the page to remove. 239 | public void RemovePage (int PageNumber) 240 | { 241 | if(curPageIndex != -1) 242 | { 243 | if(PageNumber < curPageIndex) 244 | { 245 | --curPageIndex; 246 | } 247 | else if(PageNumber == curPageIndex) 248 | { 249 | curPageIndex = -1; 250 | } 251 | } 252 | 253 | RibbonPage p = pages[PageNumber]; 254 | if(curPageIndex == -1) 255 | pages.RemoveAt (pages.Count - 1); 256 | else 257 | pages.RemoveAt (PageNumber); 258 | 259 | OnPageRemoved (new PageEventArgs (p)); 260 | } 261 | 262 | /// Returns the index of the specified page given its content widget. 263 | /// The content of the page whose index must be returned. 264 | /// The index. 265 | public int PageNum (Widget Child) 266 | { 267 | // Since it is unlikely that the widget will containe more than 268 | // a dozen pages, it is just fine to do a linear search. 269 | for(int i = 0, i_up = pages.Count ; i < i_up ; ++i) 270 | if(pages[i].Page == Child) 271 | return i; 272 | return -1; 273 | } 274 | 275 | /// Returns the index of the specified page. 276 | /// The page whose index must be returned. 277 | /// The RibbonPage. 278 | public int RibbonPageNum (RibbonPage Page) 279 | { 280 | // Since it is unlikely that the widget will containe more than 281 | // a dozen pages, it is just fine to do a linear search. 282 | for(int i = 0, i_up = pages.Count ; i < i_up ; ++i) 283 | if(pages[i] == Page) 284 | return i; 285 | return -1; 286 | } 287 | 288 | /// Sets the label widget of the specified page. 289 | /// The content of the page whose label must be modified. 290 | /// The new label widget. 291 | public void SetPageLabel (Widget Child, Widget Label) 292 | { 293 | pages[PageNum (Child)].Label = Label; 294 | } 295 | 296 | /// Gets the label widget of the specified page. 297 | /// The content of the page whose label must be returned. 298 | /// The label widget. 299 | public Widget GetPageLabel (Widget Child) 300 | { 301 | return pages[PageNum (Child)].Label; 302 | } 303 | 304 | /// Returns the content widget of the n-th page. 305 | /// Index of the page whose content has to be returned. 306 | /// The n-th page. 307 | public Widget GetNthPage (int Position) 308 | { 309 | return pages[Position].Page; 310 | } 311 | 312 | /// Returns the n-th page. 313 | /// Index of the page to return. 314 | public RibbonPage GetNthRibbonPage (int Position) 315 | { 316 | return pages[Position]; 317 | } 318 | 319 | /// Selects the specified page. 320 | /// The page to select. 321 | public void SelectRibbonPage (RibbonPage page) 322 | { 323 | int idx = RibbonPageNum (page); 324 | if(idx != -1) CurrentPageIndex = idx; 325 | OnPageSelected (new PageEventArgs (page)); 326 | } 327 | 328 | /// Selects the previous page. 329 | public void PrevPage () 330 | { 331 | int i = CurrentPageIndex; 332 | if(i > 0) CurrentPageIndex = i - 1; 333 | } 334 | 335 | /// Selects the next page. 336 | public void NextPage () 337 | { 338 | int i = CurrentPageIndex; 339 | if(i < NPages - 1) CurrentPageIndex = i + 1; 340 | } 341 | 342 | public void AddTabKeyTip (KeyTip kt) 343 | { 344 | tabKeyTips.Add (kt); 345 | } 346 | 347 | public void RemoveTabKeyTip (KeyTip kt) 348 | { 349 | tabKeyTips.Remove (kt); 350 | } 351 | 352 | public void ClearTabKeyTips () 353 | { 354 | tabKeyTips.Clear (); 355 | } 356 | 357 | protected override void ForAll (bool include_internals, Callback callback) 358 | { 359 | if(toolbar != null && toolbar.Visible) 360 | { 361 | callback (toolbar); 362 | } 363 | 364 | if(appButton != null && appButton.Visible) 365 | { 366 | callback (appButton); 367 | } 368 | 369 | if(Shortcuts != null && Shortcuts.Visible) 370 | { 371 | callback (Shortcuts); 372 | } 373 | 374 | foreach(RibbonPage p in pages) callback (p.Label); 375 | 376 | if(CurrentPage != null) 377 | { 378 | callback (CurrentPage.Page); 379 | } 380 | } 381 | 382 | protected override void OnSizeRequested (ref Requisition requisition) 383 | { 384 | base.OnSizeRequested (ref requisition); 385 | RibbonPage page = CurrentPage; 386 | 387 | double tabsWidth = 0, tabsHeight = 0; 388 | foreach(RibbonPage p in pages) 389 | { 390 | Gtk.Requisition req = p.Label.SizeRequest (); 391 | tabsWidth += req.Width; 392 | tabsHeight = Math.Max (tabsHeight, req.Height); 393 | p.LabelRequisition = req; 394 | } 395 | tabsWidth += pages.Count * 2 * tabPadding; 396 | tabsHeight += 2 * tabPadding; 397 | 398 | double headerWidth = tabsWidth; 399 | 400 | if(shortcuts != null && shortcuts.Visible) 401 | { 402 | shortcutsRequisition = shortcuts.SizeRequest (); 403 | double x = shortcutsRequisition.Width + space; 404 | headerWidth += Math.Max (x, minimalTabsHorizontalPosition); 405 | } 406 | else 407 | { 408 | shortcutsRequisition = new Gtk.Requisition (); 409 | headerWidth += minimalTabsHorizontalPosition; 410 | } 411 | 412 | headerHeight = Math.Max (tabsHeight, shortcutsRequisition.Height); 413 | 414 | bool showToolbar = toolbar != null && toolbar.Visible; 415 | bool showAppButton = appButton != null && appButton.Visible; 416 | 417 | if(showToolbar) toolbarRequisition = toolbar.SizeRequest (); 418 | if(showAppButton) appButtonRequisition = appButton.SizeRequest (); 419 | 420 | if(showToolbar) 421 | { 422 | headerHeight += 2 * space + toolbarRequisition.Height; 423 | } 424 | 425 | if(showAppButton) 426 | { 427 | headerHeight = Math.Max (headerHeight, space + appButtonRequisition.Height); 428 | } 429 | 430 | double pageWidth = 0, pageHeight = 0; 431 | if(page != null) 432 | { 433 | pageRequisition = page.Page.SizeRequest (); 434 | pageWidth = pageRequisition.Width + 2 * pagePadding; 435 | pageHeight = pageRequisition.Height + 2 * pagePadding; 436 | } 437 | else 438 | { 439 | pageRequisition = new Gtk.Requisition (); 440 | } 441 | 442 | double width = Math.Max (headerWidth, pageWidth); 443 | width = borderWidth + width + borderWidth; 444 | double height = borderWidth + headerHeight + pageHeight + borderWidth; 445 | 446 | requisition.Width = (int)Math.Ceiling (width - double.Epsilon); 447 | requisition.Height = (int)Math.Ceiling (height - double.Epsilon); 448 | } 449 | 450 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 451 | { 452 | base.OnSizeAllocated (allocation); 453 | RibbonPage page = CurrentPage; 454 | 455 | if(allocation.Height < headerHeight + borderWidth) return; 456 | 457 | double headerBottom = allocation.Y + borderWidth + headerHeight; 458 | double currentX = borderWidth; 459 | 460 | bool showToolbar = toolbar != null && toolbar.Visible; 461 | bool showAppButton = appButton != null && appButton.Visible; 462 | 463 | if(showAppButton) 464 | { 465 | Gdk.Rectangle alloc; 466 | alloc.X = (int)currentX; 467 | alloc.Y = (int)(allocation.Y + borderWidth); 468 | alloc.Width = Math.Min (appButtonRequisition.Width, (int)(allocation.Width - 2 * space)); 469 | alloc.Height = appButtonRequisition.Height; 470 | appButton.SizeAllocate (alloc); 471 | 472 | currentX += alloc.Width + space; 473 | } 474 | 475 | if(showToolbar) 476 | { 477 | Gdk.Rectangle alloc; 478 | alloc.X = (int)currentX; 479 | alloc.Y = (int)(allocation.Y + space); 480 | alloc.Width = Math.Min (toolbarRequisition.Width, (int)(allocation.Width - (alloc.X - allocation.X) - space)); 481 | alloc.Height = toolbarRequisition.Height; 482 | toolbar.SizeAllocate (alloc); 483 | } 484 | 485 | if(shortcuts != null && shortcuts.Visible) 486 | { 487 | Gdk.Rectangle alloc; 488 | alloc.X = (int)currentX; 489 | alloc.Y = (int)(headerBottom - shortcutsRequisition.Height); 490 | alloc.Width = shortcutsRequisition.Width; 491 | alloc.Height = shortcutsRequisition.Height; 492 | shortcuts.SizeAllocate (alloc); 493 | currentX += shortcutsRequisition.Width; 494 | } 495 | currentX += space; 496 | currentX = Math.Max (currentX, minimalTabsHorizontalPosition); 497 | 498 | foreach(RibbonPage p in pages) 499 | { 500 | Gdk.Rectangle alloc; 501 | alloc.X = (int)(currentX + tabPadding); 502 | alloc.Y = (int)(headerBottom - tabPadding - p.LabelRequisition.Height); 503 | alloc.Width = p.LabelRequisition.Width; 504 | alloc.Height = p.LabelRequisition.Height; 505 | p.Label.SizeAllocate (alloc); 506 | 507 | alloc.X = (int)currentX; 508 | alloc.Y = (int)(headerBottom - tabPadding - p.LabelRequisition.Height - tabPadding); 509 | alloc.Width = (int)(tabPadding + p.LabelRequisition.Width + tabPadding); 510 | alloc.Height = (int)(tabPadding + p.LabelRequisition.Height + tabPadding); 511 | p.SetLabelAllocation (alloc); 512 | 513 | currentX += p.LabelRequisition.Width + 2 * tabPadding; 514 | } 515 | 516 | bodyAllocation.X = allocation.X + (int)borderWidth; 517 | bodyAllocation.Y = (int)headerBottom; 518 | bodyAllocation.Width = allocation.Width - bodyAllocation.X - (int)borderWidth; 519 | bodyAllocation.Height = allocation.Height - bodyAllocation.Y - (int)borderWidth; 520 | 521 | if(page != null) 522 | { 523 | pageAllocation = bodyAllocation; 524 | int pad = (int)pagePadding; 525 | pageAllocation.Inflate (-pad, -pad); 526 | page.Page.SizeAllocate (pageAllocation); 527 | } 528 | else 529 | { 530 | pageAllocation = Gdk.Rectangle.Zero; 531 | } 532 | } 533 | 534 | public void ShowTopLevelKeyTips () 535 | { 536 | queuedKeyTipLevel = KeyTipLevel.TopLevel; 537 | 538 | if(appButton != null) appButton.ShowKeyTips (); 539 | if(toolbar != null) toolbar.ShowKeyTips (); 540 | 541 | int x, y; 542 | GdkWindow.GetOrigin(out x, out y); 543 | 544 | int tabLineY = (int)(y + Allocation.Y + headerHeight); 545 | foreach(KeyTip kt in tabKeyTips) 546 | { 547 | kt.ShowAt (x + kt.Target.Allocation.X + (kt.Target.Allocation.Width >> 1), tabLineY, 0.5, 0.0); 548 | } 549 | } 550 | 551 | public void ShowTabLevelKeyTips () 552 | { 553 | queuedKeyTipLevel = KeyTipLevel.Tab; 554 | 555 | } 556 | 557 | public void HideKeyTips () 558 | { 559 | queuedKeyTipLevel = KeyTipLevel.None; 560 | 561 | if(appButton != null) appButton.HideKeyTips (); 562 | if(toolbar != null) toolbar.HideKeyTips (); 563 | 564 | foreach(KeyTip kt in tabKeyTips) 565 | { 566 | kt.Hide (); 567 | } 568 | } 569 | 570 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 571 | { 572 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 573 | 574 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 575 | cr.Clip (); 576 | Draw (cr); 577 | 578 | ((IDisposable)cr.Target).Dispose (); 579 | ((IDisposable)cr).Dispose (); 580 | 581 | return base.OnExposeEvent (evnt); 582 | } 583 | 584 | protected void Draw (Context cr) 585 | { 586 | bool showToolbar = toolbar != null && toolbar.Visible; 587 | 588 | Gdk.Rectangle menuBarAllocation; 589 | menuBarAllocation.X = Allocation.X; 590 | menuBarAllocation.Y = Allocation.Y; 591 | menuBarAllocation.Width = Allocation.Width; 592 | 593 | if(showToolbar) 594 | menuBarAllocation.Height = (int)(toolbar.Allocation.Height + 2 * space); 595 | else 596 | menuBarAllocation.Height = 0; 597 | 598 | theme.DrawRibbon (cr, menuBarAllocation, bodyAllocation, roundSize, lineWidth, this); 599 | } 600 | 601 | protected virtual void OnPageSelected (PageEventArgs args) 602 | { 603 | if(PageSelected != null) PageSelected (this, args); 604 | } 605 | 606 | protected virtual void OnPageAdded (PageEventArgs args) 607 | { 608 | if(PageAdded != null) PageAdded (this, args); 609 | } 610 | 611 | protected virtual void OnPageMoved (PageEventArgs args) 612 | { 613 | if(PageMoved != null) PageMoved (this, args); 614 | } 615 | 616 | protected virtual void OnPageRemoved (PageEventArgs args) 617 | { 618 | if(PageRemoved != null) PageRemoved (this, args); 619 | } 620 | 621 | /// Ribbon page. 622 | public class RibbonPage 623 | { 624 | private Ribbon parent; 625 | private Widget label, page; 626 | private Requisition labelReq; 627 | private Gdk.Rectangle labelAlloc; 628 | private List tabKeyTips; 629 | 630 | /// Label widget of the page. 631 | public Widget Label 632 | { 633 | set 634 | { 635 | if(label != null) label.Unparent (); 636 | label = value; 637 | if(label != null) label.Parent = parent; 638 | } 639 | get { return label; } 640 | } 641 | 642 | /// Widget used as the content of the page. 643 | public Widget Page 644 | { 645 | set { page = value; } 646 | get { return page; } 647 | } 648 | 649 | internal Requisition LabelRequisition 650 | { 651 | set { labelReq = value; } 652 | get { return labelReq; } 653 | } 654 | 655 | public Gdk.Rectangle LabelAllocation 656 | { 657 | get { return labelAlloc; } 658 | } 659 | 660 | public RibbonPage (Ribbon Parent, Widget Page, Widget Label) 661 | { 662 | this.parent = Parent; 663 | this.Label = Label; 664 | this.Page = Page; 665 | this.tabKeyTips = new List (); 666 | } 667 | 668 | public void SetLabelAllocation (Gdk.Rectangle r) 669 | { 670 | labelAlloc = r; 671 | } 672 | } 673 | } 674 | } 675 | -------------------------------------------------------------------------------- /Ribbons/RibbonGroup.cs: -------------------------------------------------------------------------------- 1 | using Cairo; 2 | using Gtk; 3 | using System; 4 | 5 | namespace Ribbons 6 | { 7 | /// Ribbon group. 8 | public class RibbonGroup : Bin 9 | { 10 | protected Theme theme = Theme.DefaultTheme; 11 | protected string lbl; 12 | protected Pango.Layout lbl_layout; 13 | protected Button expandButton; 14 | protected EventHandler expandHandler; 15 | 16 | private double barHeight, barWidth; 17 | 18 | protected double childPadding = 1.0; 19 | protected double lineWidth = 1.0; 20 | protected double space = 2.0; 21 | protected Position labelPosition = Position.Bottom; 22 | 23 | /// Displayed label. 24 | public string Label 25 | { 26 | set 27 | { 28 | lbl = value; 29 | 30 | if(lbl == null) 31 | lbl_layout = null; 32 | else if(lbl_layout == null) 33 | lbl_layout = CreatePangoLayout (this.lbl); 34 | else 35 | lbl_layout.SetText (lbl); 36 | 37 | QueueDraw (); 38 | } 39 | get { return lbl; } 40 | } 41 | 42 | /// Expand event. 43 | /// Fired whenever the expand button is clicked. 44 | [GLib.Signal("expanded")] 45 | public event EventHandler Expand 46 | { 47 | add 48 | { 49 | expandHandler += value; 50 | expandButton.Visible = expandHandler != null; 51 | } 52 | remove 53 | { 54 | expandHandler -= value; 55 | expandButton.Visible = expandHandler != null; 56 | } 57 | } 58 | 59 | /// Theme used to draw the widget. 60 | public Theme Theme 61 | { 62 | set 63 | { 64 | theme = value; 65 | QueueDraw (); 66 | } 67 | get { return theme; } 68 | } 69 | 70 | /// Position of the label. 71 | public Position LabelPosition 72 | { 73 | set 74 | { 75 | labelPosition = value; 76 | QueueDraw (); 77 | } 78 | get { return labelPosition; } 79 | } 80 | 81 | /// Default constructor. 82 | public RibbonGroup () 83 | { 84 | // This is a No Window widget => it does not have its own Gdk Window => it can be transparent 85 | this.SetFlag (WidgetFlags.NoWindow); 86 | 87 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 88 | 89 | Label = null; 90 | HeightRequest = 92; 91 | 92 | expandButton = new Button ("\u21F2"); 93 | expandButton.Padding = 0; 94 | expandButton.Visible = false; 95 | expandButton.Parent = this; 96 | expandButton.Clicked += delegate (object Sender, EventArgs e) 97 | { 98 | OnExpand (e); 99 | }; 100 | } 101 | 102 | public override void Dispose () 103 | { 104 | base.Dispose (); 105 | if(lbl_layout != null) lbl_layout.Dispose (); 106 | } 107 | 108 | protected virtual void OnExpand (EventArgs e) 109 | { 110 | if(expandHandler != null) expandHandler (this, e); 111 | } 112 | 113 | protected override void ForAll (bool include_internals, Callback callback) 114 | { 115 | base.ForAll (include_internals, callback); 116 | if(expandButton != null && expandButton.Visible) callback (expandButton); 117 | } 118 | 119 | protected override void OnSizeRequested (ref Requisition requisition) 120 | { 121 | base.OnSizeRequested (ref requisition); 122 | 123 | int lw, lh; 124 | 125 | if(labelPosition == Position.Top || labelPosition == Position.Bottom) 126 | lbl_layout.GetPixelSize (out lw, out lh); 127 | else 128 | lbl_layout.GetPixelSize (out lh, out lw); 129 | 130 | double frameSize = 2*lineWidth + childPadding; 131 | 132 | barHeight = lh + 2 * space; 133 | barWidth = lw + 2 * space; 134 | 135 | if(expandButton != null && expandButton.Visible) 136 | { 137 | if(labelPosition == Position.Top || labelPosition == Position.Bottom) 138 | expandButton.SetSizeRequest (lh, lh); 139 | else 140 | expandButton.SetSizeRequest (lw, lw); 141 | 142 | expandButton.SizeRequest (); 143 | 144 | if(labelPosition == Position.Top || labelPosition == Position.Bottom) 145 | barWidth += expandButton.WidthRequest + (int)space; 146 | else 147 | barHeight += expandButton.HeightRequest + (int)space; 148 | } 149 | 150 | Requisition childRequisition = new Requisition (); 151 | 152 | if(Child != null && Child.Visible) 153 | { 154 | if(HeightRequest != -1) 155 | { 156 | int left = HeightRequest; 157 | if(labelPosition == Position.Top || labelPosition == Position.Bottom) 158 | left -= (int)(2 * frameSize + barHeight); 159 | else 160 | left -= (int)(2 * frameSize); 161 | 162 | Child.HeightRequest = left; 163 | } 164 | if(WidthRequest != -1) 165 | { 166 | int left = WidthRequest; 167 | if(labelPosition == Position.Top || labelPosition == Position.Bottom) 168 | left -= (int)(2 * frameSize); 169 | else 170 | left -= (int)(2 * frameSize + barWidth); 171 | 172 | Child.WidthRequest = left; 173 | } 174 | childRequisition = Child.SizeRequest (); 175 | } 176 | 177 | if(WidthRequest == -1) 178 | { 179 | if(Child != null && Child.Visible) 180 | { 181 | requisition.Width = childRequisition.Width + (int)(2 * frameSize); 182 | 183 | if(labelPosition == Position.Left || labelPosition == Position.Right) 184 | requisition.Width += (int)barWidth; 185 | } 186 | else 187 | { 188 | requisition.Width = (int)(2 * frameSize + barWidth); 189 | } 190 | } 191 | 192 | if(HeightRequest == -1) 193 | { 194 | if(Child != null && Child.Visible) 195 | { 196 | requisition.Height = childRequisition.Height + (int)(2 * frameSize); 197 | 198 | if(labelPosition == Position.Top || labelPosition == Position.Bottom) 199 | requisition.Height += (int)barHeight; 200 | } 201 | else 202 | { 203 | requisition.Height = (int)(2 * frameSize + barHeight); 204 | } 205 | } 206 | } 207 | 208 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 209 | { 210 | base.OnSizeAllocated (allocation); 211 | 212 | if(expandButton != null && expandButton.Visible) 213 | { 214 | double frameSize = 2*lineWidth + space; 215 | Gdk.Rectangle r; 216 | r.Height = expandButton.HeightRequest; 217 | r.Width = expandButton.WidthRequest; 218 | 219 | if(labelPosition == Position.Left) 220 | r.X = allocation.X + (int)frameSize; 221 | else 222 | r.X = allocation.X + allocation.Width - r.Width - (int)frameSize; 223 | 224 | if(labelPosition == Position.Top) 225 | r.Y = allocation.Y + (int)frameSize; 226 | else 227 | r.Y = allocation.Y + allocation.Height - r.Height - (int)frameSize; 228 | 229 | expandButton.SizeAllocate (r); 230 | } 231 | 232 | if(Child != null && Child.Visible) 233 | { 234 | double frameSize = 2*lineWidth + childPadding; 235 | int wi = allocation.Width - (int)(2 * frameSize); 236 | int he = allocation.Height - (int)(2 * frameSize); 237 | 238 | Gdk.Rectangle r = new Gdk.Rectangle (allocation.X + (int)frameSize, allocation.Y + (int)frameSize, wi, he); 239 | 240 | if(labelPosition == Position.Top) 241 | r.Y += (int)barHeight; 242 | else if(labelPosition == Position.Left) 243 | r.X += (int)barWidth; 244 | 245 | if(labelPosition == Position.Top || LabelPosition == Position.Bottom) 246 | r.Height -= (int)barHeight; 247 | else 248 | r.Width -= (int)barWidth; 249 | 250 | Child.SizeAllocate (r); 251 | } 252 | } 253 | 254 | protected void Draw (Context cr) 255 | { 256 | Rectangle rect = new Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 257 | theme.DrawGroup (cr, rect, 4.0, lineWidth, space, lbl_layout, expandButton, this); 258 | } 259 | 260 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 261 | { 262 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 263 | 264 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 265 | cr.Clip (); 266 | Draw (cr); 267 | 268 | ((IDisposable)cr.Target).Dispose (); 269 | ((IDisposable)cr).Dispose (); 270 | 271 | return base.OnExposeEvent (evnt); 272 | } 273 | } 274 | } -------------------------------------------------------------------------------- /Ribbons/Ribbons.mdp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | Ribbons.RibbonButton 66 | Ribbons.Label 67 | 68 | 69 | -------------------------------------------------------------------------------- /Ribbons/SyntheticEventCrossing.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | using Gdk; 4 | 5 | namespace Ribbons 6 | { 7 | /// Managed EventCrossing implementation. 8 | [StructLayout(LayoutKind.Sequential)] 9 | internal struct SyntheticEventCrossing 10 | { 11 | [MarshalAs(UnmanagedType.SysInt)] 12 | private int type; // GdkEventType 13 | private IntPtr window; // GdkWindow 14 | private byte send_event; 15 | private IntPtr subwindow; // GdkWindow 16 | private UInt32 time; 17 | private double x; 18 | private double y; 19 | private double root_x; 20 | private double root_y; 21 | [MarshalAs(UnmanagedType.SysInt)] 22 | private int mode; // GdkCrossingMode 23 | [MarshalAs(UnmanagedType.SysInt)] 24 | private int detail; // GdkNotifyType 25 | [MarshalAs(UnmanagedType.SysInt)] 26 | private int focus; // gboolean 27 | [MarshalAs(UnmanagedType.SysUInt)] 28 | private uint state; 29 | 30 | public EventType Type 31 | { 32 | set { type = (int)value; } 33 | get { return (EventType)type; } 34 | } 35 | 36 | public Window Window 37 | { 38 | set { window = value == null ? IntPtr.Zero : value.Handle; } 39 | get { return window == IntPtr.Zero ? null : new Window (window); } 40 | } 41 | 42 | public bool SendEvent 43 | { 44 | set { send_event = value ? (byte)1 : (byte)0; } 45 | get { return send_event != 0; } 46 | } 47 | 48 | public Window Subwindow 49 | { 50 | set { subwindow = value == null ? IntPtr.Zero : value.Handle; } 51 | get { return subwindow == IntPtr.Zero ? null : new Window (subwindow); } 52 | } 53 | 54 | public UInt32 Time 55 | { 56 | set { time = value; } 57 | get { return time; } 58 | } 59 | 60 | public double X 61 | { 62 | set { x = value; } 63 | get { return x; } 64 | } 65 | 66 | public double Y 67 | { 68 | set { y = value; } 69 | get { return y; } 70 | } 71 | 72 | public double XRoot 73 | { 74 | set { root_x = value; } 75 | get { return root_x; } 76 | } 77 | 78 | public double YRoot 79 | { 80 | set { root_y = value; } 81 | get { return root_y; } 82 | } 83 | 84 | public CrossingMode Mode 85 | { 86 | set { mode = (int)value; } 87 | get { return (CrossingMode)mode; } 88 | } 89 | 90 | public NotifyType Detail 91 | { 92 | set { detail = (int)value; } 93 | get { return (NotifyType)detail; } 94 | } 95 | 96 | public bool Focus 97 | { 98 | set { focus = value ? 1 : 0; } 99 | get { return focus != 0; } 100 | } 101 | 102 | public ModifierType State 103 | { 104 | set { state = (uint)value; } 105 | get { return (ModifierType)state; } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Ribbons/SyntheticWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gdk; 4 | using Gtk; 5 | 6 | namespace Ribbons 7 | { 8 | /// Window generating synthetic events to window-less widgets. 9 | public class SyntheticWindow : Gtk.Window 10 | { 11 | private List lastHoveredWidgets; 12 | 13 | public SyntheticWindow (Gtk.WindowType type) : base (type) 14 | { 15 | lastHoveredWidgets = new List (); 16 | } 17 | 18 | protected override bool OnWidgetEvent (Gdk.Event evnt) 19 | { 20 | // This method is hooked to block the event as soon as possible if required 21 | 22 | if(evnt.Window.Equals (this.GdkWindow)) 23 | { 24 | switch(evnt.Type) 25 | { 26 | case Gdk.EventType.ButtonPress: 27 | case Gdk.EventType.ButtonRelease: 28 | case Gdk.EventType.ThreeButtonPress: 29 | case Gdk.EventType.TwoButtonPress: 30 | Gdk.EventButton eb = new Gdk.EventButton (evnt.Handle); 31 | return PropagateEventGivenCoordinate (evnt, eb.X, eb.XRoot, eb.Y, eb.YRoot); 32 | 33 | case Gdk.EventType.MotionNotify: 34 | Gdk.EventMotion em = new Gdk.EventMotion (evnt.Handle); 35 | return PropagateEventGivenCoordinate (evnt, em.X, em.XRoot, em.Y, em.YRoot); 36 | 37 | case Gdk.EventType.LeaveNotify: 38 | foreach(Widget w in lastHoveredWidgets) 39 | { 40 | w.ProcessEvent (evnt); 41 | } 42 | lastHoveredWidgets.Clear(); 43 | return base.OnWidgetEvent (evnt); 44 | } 45 | } 46 | return base.OnWidgetEvent (evnt); 47 | } 48 | 49 | private bool PropagateEventGivenCoordinate (Gdk.Event evnt, double X, double XRoot, double Y, double YRoot) 50 | { 51 | int x = (int)X, y = (int)Y; 52 | Container current = this; // Current container containing the coordinate 53 | Widget match = this; // Current match for the position 54 | int matchedPos = 0; // Current position in lastHoveredWidgets 55 | 56 | while(matchedPos < lastHoveredWidgets.Count) 57 | { 58 | Widget candidate = lastHoveredWidgets[matchedPos]; 59 | if(candidate.Parent == current) // Is it still a child of the current container ? 60 | { 61 | Gdk.Rectangle alloc = candidate.Allocation; 62 | if(!alloc.Contains (x, y)) // Does it contain the coordinate ? 63 | { 64 | break; 65 | } 66 | } 67 | current = candidate as Container; 68 | match = candidate; 69 | ++matchedPos; 70 | } 71 | 72 | if(matchedPos < lastHoveredWidgets.Count) // Not all widgets match 73 | { 74 | // Send a leave notify 75 | SendSyntheticEvent (EventType.LeaveNotify, evnt, X, XRoot, Y, YRoot, lastHoveredWidgets, matchedPos); 76 | 77 | // Remove them 78 | lastHoveredWidgets.RemoveRange (matchedPos, lastHoveredWidgets.Count - matchedPos); 79 | } 80 | 81 | while (current != null) 82 | { 83 | Container next = null; 84 | foreach(Widget child in current.Children) 85 | { 86 | if(child.IsNoWindow) 87 | { 88 | Gdk.Rectangle alloc = child.Allocation; 89 | if(alloc.Contains (x, y)) 90 | { 91 | lastHoveredWidgets.Add (child); 92 | match = child; 93 | next = child as Container; 94 | break; 95 | } 96 | } 97 | } 98 | current = next; 99 | } 100 | 101 | if(matchedPos < lastHoveredWidgets.Count) // New widgets have been found 102 | { 103 | // Send an enter notify 104 | SendSyntheticEvent (EventType.EnterNotify, evnt, X, XRoot, Y, YRoot, lastHoveredWidgets, matchedPos); 105 | } 106 | 107 | if(match == this) // No widget found, the window keeps the event 108 | { 109 | return base.OnWidgetEvent (evnt); 110 | } 111 | else // A widget has been found, let's send it the event 112 | { 113 | match.ProcessEvent (evnt); 114 | return true; 115 | } 116 | } 117 | 118 | private void SendSyntheticEvent (EventType Type, Event OriginalEvent, double X, double XRoot, double Y, double YRoot, IList Widgets, int Index) 119 | { 120 | SyntheticEventCrossing se = new SyntheticEventCrossing(); 121 | se.Detail = NotifyType.Ancestor; 122 | se.Focus = false; 123 | se.Mode = CrossingMode.Normal; 124 | se.SendEvent = false; 125 | se.State = ModifierType.None; 126 | se.Subwindow = null; 127 | //se.Time = DateTime.Now.Ticks / 10000; // TODO: the real value shoud be the uptime I think 128 | se.Time = 0; 129 | se.Type = Type; 130 | se.Window = OriginalEvent.Window; 131 | se.X = X; 132 | se.XRoot = XRoot; 133 | se.Y = Y; 134 | se.YRoot = YRoot; 135 | 136 | unsafe 137 | { 138 | Event managedEvent = new Event(new IntPtr(&se)); 139 | 140 | for(int i = Index ; i < Widgets.Count ; ++i) 141 | { 142 | Widgets[i].ProcessEvent (managedEvent); 143 | } 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Ribbons/Tile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// The Tile widget. 8 | public abstract class Tile : Widget 9 | { 10 | protected Theme theme = new Theme (); 11 | private bool selected; 12 | private uint borderWidth; 13 | 14 | /// Gets or sets the width of the border. 15 | public uint BorderWidth 16 | { 17 | set 18 | { 19 | borderWidth = value; 20 | QueueDraw (); 21 | } 22 | get { return borderWidth; } 23 | } 24 | 25 | /// Gets or sets the state of the Tile. 26 | public bool Selected 27 | { 28 | set 29 | { 30 | selected = value; 31 | QueueDraw (); 32 | } 33 | get { return selected; } 34 | } 35 | 36 | /// Fired when the Tile has been clicked. 37 | public event EventHandler Clicked; 38 | 39 | /// Theme used to draw the widget. 40 | public Theme Theme 41 | { 42 | set 43 | { 44 | theme = value; 45 | QueueDraw (); 46 | } 47 | get { return theme; } 48 | } 49 | 50 | /// Default constructor. 51 | public Tile () 52 | { 53 | this.SetFlag (WidgetFlags.NoWindow); 54 | 55 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 56 | 57 | this.selected = false; 58 | this.BorderWidth = 4; 59 | } 60 | 61 | /// Creates a carbon copy of the current Tile. 62 | public abstract Tile Copy (); 63 | 64 | /// Fires the Click event. 65 | public void Click () 66 | { 67 | if(Clicked != null) Clicked (this, EventArgs.Empty); 68 | } 69 | 70 | protected override void OnSizeRequested (ref Requisition requisition) 71 | { 72 | base.OnSizeRequested (ref requisition); 73 | } 74 | 75 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 76 | { 77 | base.OnSizeAllocated (allocation); 78 | } 79 | 80 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 81 | { 82 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 83 | 84 | Cairo.Rectangle area = new Cairo.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 85 | Cairo.Rectangle allocation = new Cairo.Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 86 | Cairo.Rectangle contentArea = new Cairo.Rectangle (allocation.X + BorderWidth, allocation.Y + BorderWidth, allocation.Width - 2 * BorderWidth, allocation.Height - 2 * BorderWidth); 87 | 88 | cr.Rectangle (area); 89 | cr.Clip (); 90 | theme.DrawTile (cr, allocation, contentArea, this); 91 | 92 | DrawContent (cr, contentArea); 93 | 94 | ((IDisposable)cr.Target).Dispose (); 95 | ((IDisposable)cr).Dispose (); 96 | 97 | return base.OnExposeEvent (evnt); 98 | } 99 | 100 | /// 101 | /// Draws the content of the tile. 102 | /// 103 | /// Cairo context to be used to draw the content. 104 | /// Area that can be painted. 105 | public abstract void DrawContent (Cairo.Context Context, Cairo.Rectangle Area); 106 | 107 | protected override bool OnButtonPressEvent (Gdk.EventButton evnt) 108 | { 109 | bool ret = base.OnButtonPressEvent (evnt); 110 | 111 | this.QueueDraw (); 112 | return ret; 113 | } 114 | 115 | protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt) 116 | { 117 | bool ret = base.OnButtonReleaseEvent (evnt); 118 | Click (); 119 | this.QueueDraw (); 120 | return ret; 121 | } 122 | 123 | protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt) 124 | { 125 | bool ret = base.OnEnterNotifyEvent (evnt); 126 | 127 | this.QueueDraw (); 128 | return ret; 129 | } 130 | 131 | protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt) 132 | { 133 | bool ret = base.OnLeaveNotifyEvent (evnt); 134 | 135 | this.QueueDraw (); 136 | return ret; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /Ribbons/TileSelectedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public class TileSelectedEventArgs 6 | { 7 | private Tile selTile; 8 | 9 | /// The tile that has been selected. 10 | public Tile SelectedTile 11 | { 12 | get { return selTile; } 13 | } 14 | 15 | public TileSelectedEventArgs (Tile SelectedTile) 16 | { 17 | selTile = SelectedTile; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Ribbons/TileSelectedHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Ribbons 4 | { 5 | public delegate void TileSelectedHandler(object Sender, TileSelectedEventArgs e); 6 | } 7 | -------------------------------------------------------------------------------- /Ribbons/ToggleButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// Toggle button to be used in Ribbons. 8 | public class ToggleButton : BaseButton 9 | { 10 | private bool value; 11 | private bool displayArrow; 12 | 13 | protected const double lineWidth = 1.0; 14 | protected const double arrowPadding = 2.0; 15 | protected const double arrowSize = 8.0; 16 | 17 | public event EventHandler ValueChanged; 18 | 19 | public bool Value 20 | { 21 | set 22 | { 23 | if(this.value != value) 24 | { 25 | this.value = value; 26 | OnValueChanged (); 27 | QueueDraw (); 28 | } 29 | } 30 | get { return value; } 31 | } 32 | 33 | public bool DisplayArrow 34 | { 35 | set 36 | { 37 | if(this.displayArrow != value) 38 | { 39 | this.displayArrow = value; 40 | OnValueChanged (); 41 | QueueDraw (); 42 | } 43 | } 44 | get { return displayArrow; } 45 | } 46 | 47 | /// Default constructor. 48 | public ToggleButton () 49 | { 50 | this.SetFlag (WidgetFlags.NoWindow); 51 | 52 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 53 | 54 | this.Padding = 2; 55 | this.ImagePosition = PositionType.Top; 56 | this.isSmall = false; 57 | this.enable = true; 58 | this.value = false; 59 | } 60 | 61 | /// Constructor given a label to display. 62 | /// Label to display. 63 | public ToggleButton (string Label) : this () 64 | { 65 | this.Label = Label; 66 | } 67 | 68 | /// Constructor given an image to display. 69 | /// Image to display 70 | public ToggleButton (Image Image) : this () 71 | { 72 | this.Image = Image; 73 | } 74 | 75 | /// Constructor given a label and an image to display. 76 | /// Image to display. 77 | /// Label to display. 78 | public ToggleButton (Image Image, string Label) : this () 79 | { 80 | this.Image = Image; 81 | this.Label = Label; 82 | } 83 | 84 | /// Constructs a Button from a stock. 85 | /// Name of the stock. 86 | /// true if the image should be large, false otherwise. 87 | public static ToggleButton FromStockIcon (string Name, bool Large) 88 | { 89 | Image img = new Image (Name, Large ? IconSize.LargeToolbar : IconSize.SmallToolbar); 90 | ToggleButton btn = new ToggleButton (img); 91 | if(!Large) btn.ImagePosition = PositionType.Left; 92 | return btn; 93 | } 94 | 95 | /// Constructs a Button from a stock. 96 | /// Name of the stock. 97 | /// Label to display. 98 | /// true if the image should be large, false otherwise. 99 | public static ToggleButton FromStockIcon (string Name, string Label, bool Large) 100 | { 101 | Image img = new Image (Name, Large ? IconSize.LargeToolbar : IconSize.SmallToolbar); 102 | ToggleButton btn = new ToggleButton (img, Label); 103 | if(!Large) btn.ImagePosition = PositionType.Left; 104 | return btn; 105 | } 106 | 107 | protected override void BindedWidget_ButtonPressEvent (object sender, ButtonPressEventArgs evnt) 108 | { 109 | ProcessEvent (evnt.Event); 110 | } 111 | 112 | protected override void BindedWidget_ButtonReleaseEvent (object sender, ButtonReleaseEventArgs evnt) 113 | { 114 | ProcessEvent (evnt.Event); 115 | Value = !Value; 116 | } 117 | 118 | protected override void OnSizeRequested (ref Requisition requisition) 119 | { 120 | base.OnSizeRequested (ref requisition); 121 | 122 | Requisition childRequisition = new Requisition (); 123 | if(Child != null && Child.Visible) 124 | { 125 | childRequisition = Child.SizeRequest (); 126 | } 127 | 128 | if(displayArrow) 129 | { 130 | int arrowSpace = (int)(arrowSize + 2 * (lineWidth + arrowPadding)); 131 | 132 | if(imgPos == PositionType.Top || imgPos == PositionType.Bottom) 133 | { 134 | childRequisition.Height += arrowSpace; 135 | } 136 | else 137 | { 138 | childRequisition.Width += arrowSpace; 139 | } 140 | } 141 | 142 | if(HeightRequest == -1) 143 | { 144 | requisition.Height = childRequisition.Height + (int)(lineWidth * 4 + padding * 2); 145 | } 146 | if(WidthRequest == -1) 147 | { 148 | requisition.Width = childRequisition.Width + (int)(lineWidth * 4 + padding * 2); 149 | } 150 | } 151 | 152 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 153 | { 154 | base.OnSizeAllocated (allocation); 155 | 156 | allocation.X += (int)(lineWidth * 2 + padding); 157 | allocation.Y += (int)(lineWidth * 2 + padding); 158 | allocation.Height -= (int)(lineWidth * 4 + padding * 2); 159 | allocation.Width -= (int)(lineWidth * 4 + padding * 2); 160 | 161 | if(displayArrow) 162 | { 163 | int arrowSpace = (int)(arrowSize + 2 * (lineWidth + arrowPadding)); 164 | 165 | if(imgPos == PositionType.Top || imgPos == PositionType.Bottom) 166 | { 167 | allocation.Height -= arrowSpace; 168 | } 169 | else 170 | { 171 | allocation.Width -= arrowSpace; 172 | } 173 | } 174 | 175 | if(allocation.Height < 0) allocation.Height = 0; 176 | if(allocation.Width < 0) allocation.Width = 0; 177 | 178 | if(Child != null && Child.Visible) 179 | { 180 | Child.SizeAllocate (allocation); 181 | } 182 | } 183 | 184 | protected override bool OnExposeEvent (Gdk.EventExpose evnt) 185 | { 186 | Context cr = Gdk.CairoHelper.Create (this.GdkWindow); 187 | 188 | cr.Rectangle (evnt.Area.X, evnt.Area.Y, evnt.Area.Width, evnt.Area.Height); 189 | cr.Clip (); 190 | Draw (cr); 191 | 192 | ((IDisposable)cr.Target).Dispose (); 193 | ((IDisposable)cr).Dispose (); 194 | 195 | return base.OnExposeEvent (evnt); 196 | } 197 | 198 | protected void Draw (Context cr) 199 | { 200 | Rectangle rect = new Rectangle (Allocation.X, Allocation.Y, Allocation.Width, Allocation.Height); 201 | double roundSize = isSmall ? 2.0 : 3.0; 202 | Theme.ButtonState s = this.state; 203 | if(this.value) s = Theme.ButtonState.Pressed; 204 | theme.DrawButton (cr, rect, s, roundSize, lineWidth, displayArrow ? arrowSize : 0, arrowPadding, false, this); 205 | } 206 | 207 | protected virtual void OnValueChanged () 208 | { 209 | if(ValueChanged != null) ValueChanged (this, EventArgs.Empty); 210 | } 211 | 212 | protected override bool OnButtonPressEvent (Gdk.EventButton evnt) 213 | { 214 | bool ret = base.OnButtonPressEvent (evnt); 215 | state = Theme.ButtonState.Pressed; 216 | if(!enable) state = Theme.ButtonState.Default; 217 | this.QueueDraw (); 218 | return ret; 219 | } 220 | 221 | protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt) 222 | { 223 | bool ret = base.OnButtonReleaseEvent (evnt); 224 | state = Theme.ButtonState.Hover; 225 | if(!enable) state = Theme.ButtonState.Default; 226 | this.QueueDraw (); 227 | return ret; 228 | } 229 | 230 | protected override bool OnEnterNotifyEvent (Gdk.EventCrossing evnt) 231 | { 232 | bool ret = base.OnEnterNotifyEvent (evnt); 233 | state = Theme.ButtonState.Hover; 234 | if(!enable) state = Theme.ButtonState.Default; 235 | this.QueueDraw (); 236 | return ret; 237 | } 238 | 239 | protected override bool OnLeaveNotifyEvent (Gdk.EventCrossing evnt) 240 | { 241 | bool ret = base.OnLeaveNotifyEvent (evnt); 242 | state = Theme.ButtonState.Default; 243 | this.QueueDraw (); 244 | return ret; 245 | } 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /Ribbons/ToolBox.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// ToolBox containing several widgets displayed in rows. 8 | public class ToolBox : Container 9 | { 10 | private List widgets; 11 | private Gtk.Requisition[] requisitions; 12 | private int spacing; 13 | 14 | /// Gets or sets the spacing between children. 15 | public int Spacing 16 | { 17 | set 18 | { 19 | spacing = value; 20 | QueueDraw (); 21 | } 22 | get { return spacing; } 23 | } 24 | 25 | /// Default constructor. 26 | public ToolBox () 27 | { 28 | this.widgets = new List (); 29 | 30 | this.SetFlag (WidgetFlags.NoWindow); 31 | 32 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 33 | 34 | spacing = 2; 35 | } 36 | 37 | /// Adds a widget before all existing widgets. 38 | /// The widget to add. 39 | public void Prepend (Widget w) 40 | { 41 | Insert (w, 0); 42 | } 43 | 44 | /// Adds a widget after all existing widgets. 45 | /// The widget to add. 46 | public void Append (Widget w) 47 | { 48 | Insert (w, -1); 49 | } 50 | 51 | /// Inserts a widget at the specified location. 52 | /// The widget to add. 53 | /// The index (starting at 0) at which the widget must be inserted, or -1 to insert the widget after all existing widgets. 54 | public void Insert (Widget w, int WidgetIndex) 55 | { 56 | w.Parent = this; 57 | w.Visible = true; 58 | 59 | if(WidgetIndex == -1) 60 | widgets.Add (w); 61 | else 62 | widgets.Insert (WidgetIndex, w); 63 | 64 | ShowAll (); 65 | } 66 | 67 | /// Removes the widget at the specified index. 68 | /// Index of the widget to remove. 69 | public void Remove (int WidgetIndex) 70 | { 71 | widgets[WidgetIndex].Parent = null; 72 | 73 | if(WidgetIndex == -1) 74 | widgets.RemoveAt (widgets.Count - 1); 75 | else 76 | widgets.RemoveAt (WidgetIndex); 77 | 78 | ShowAll (); 79 | } 80 | 81 | protected override void ForAll (bool include_internals, Callback callback) 82 | { 83 | foreach(Widget w in widgets) 84 | { 85 | if(w.Visible) callback (w); 86 | } 87 | } 88 | 89 | protected override void OnSizeRequested (ref Requisition requisition) 90 | { 91 | base.OnSizeRequested (ref requisition); 92 | 93 | if(requisitions == null || requisitions.Length != widgets.Count) 94 | { 95 | requisitions = new Gtk.Requisition[widgets.Count]; 96 | } 97 | 98 | int totalWidth = 0, rowHeight = 0; 99 | foreach(Widget w in widgets) 100 | { 101 | if(w.Visible) 102 | { 103 | rowHeight = Math.Max (rowHeight, w.SizeRequest ().Height); 104 | } 105 | } 106 | 107 | int i = 0; 108 | foreach(Widget w in widgets) 109 | { 110 | if(w.Visible) 111 | { 112 | w.HeightRequest = rowHeight; 113 | requisitions[i] = w.SizeRequest (); 114 | totalWidth += requisitions[i].Width + spacing; 115 | } 116 | ++i; 117 | } 118 | totalWidth -= spacing; 119 | 120 | if(WidthRequest != -1 && HeightRequest != -1) 121 | { 122 | requisition.Width = WidthRequest; 123 | requisition.Height = HeightRequest; 124 | } 125 | else if(WidthRequest != -1) 126 | { 127 | int totalHeight = rowHeight, curWidth = 0; 128 | int availWidth = WidthRequest - 2*(int)BorderWidth; 129 | 130 | i = 0; 131 | foreach(Widget w in widgets) 132 | { 133 | if(w.Visible) 134 | { 135 | Gtk.Requisition r = requisitions[i]; 136 | 137 | if(curWidth == 0 || curWidth + r.Width <= availWidth) 138 | { // Continue current line 139 | curWidth += r.Width; 140 | if(curWidth != 0) curWidth += spacing; 141 | } 142 | else 143 | { // Start new line 144 | totalHeight += rowHeight + spacing; 145 | curWidth = 0; 146 | } 147 | } 148 | ++i; 149 | } 150 | 151 | requisition.Width = WidthRequest; 152 | requisition.Height = totalHeight + 2*(int)BorderWidth; 153 | } 154 | else 155 | { 156 | int rowsLeft = (int)Math.Floor ((double)(HeightRequest + spacing) / (double)(rowHeight + spacing)); 157 | if(rowsLeft == 0) rowsLeft = 1; 158 | int widthLeft = totalWidth; 159 | int curWidth = 0, maxWidth = 0; 160 | int minWidth = widthLeft / rowsLeft; 161 | 162 | i = 0; 163 | int currentWidgetCounter = 0; 164 | foreach(Widget w in widgets) 165 | { 166 | if(w.Visible) 167 | { 168 | Gtk.Requisition r = requisitions[i]; 169 | 170 | widthLeft -= r.Width; 171 | curWidth += r.Width; 172 | ++currentWidgetCounter; 173 | 174 | if(curWidth >= minWidth) 175 | { // Start new line 176 | curWidth += (currentWidgetCounter - 1) * spacing; 177 | maxWidth = Math.Max (maxWidth, curWidth); 178 | curWidth = 0; 179 | --rowsLeft; 180 | if(rowsLeft == 0) break; 181 | minWidth = widthLeft / rowsLeft; 182 | currentWidgetCounter = 0; 183 | } 184 | } 185 | ++i; 186 | } 187 | 188 | requisition.Width = maxWidth + 2*(int)BorderWidth; 189 | 190 | if(HeightRequest == -1) 191 | requisition.Height = rowHeight; 192 | else 193 | requisition.Height = HeightRequest; 194 | } 195 | } 196 | 197 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 198 | { 199 | base.OnSizeAllocated (allocation); 200 | 201 | int right = allocation.X + allocation.Width - (int)BorderWidth; 202 | int left = allocation.X + (int)BorderWidth; 203 | int bottom = allocation.Y + allocation.Height - (int)BorderWidth; 204 | int x = left, rowY = allocation.Y + (int)BorderWidth; 205 | int maxHeight = 0; 206 | 207 | int i = 0; 208 | foreach(Widget w in widgets) 209 | { 210 | if(w.Visible) 211 | { 212 | Gdk.Rectangle r; 213 | r.Width = requisitions[i].Width; 214 | r.Height = requisitions[i].Height; 215 | 216 | if(x > left && x + r.Width > right) 217 | { 218 | rowY += maxHeight + spacing; 219 | maxHeight = 0; 220 | x = left; 221 | } 222 | 223 | r.X = x; 224 | r.Y = rowY; 225 | r.Width = Math.Min (right, r.X + r.Width) - r.X; 226 | r.Height = Math.Min (bottom, r.Y + r.Height) - r.Y; 227 | w.SizeAllocate (r); 228 | 229 | x += r.Width + spacing; 230 | maxHeight = Math.Max (maxHeight, r.Height); 231 | } 232 | ++i; 233 | } 234 | } 235 | } 236 | } 237 | -------------------------------------------------------------------------------- /Ribbons/ToolPack.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Cairo; 4 | using Gtk; 5 | 6 | namespace Ribbons 7 | { 8 | /// Set of ribbon buttons packed together. 9 | public class ToolPack : Container 10 | { 11 | private List buttons; 12 | private int[] widths; 13 | 14 | /// Default constructor. 15 | public ToolPack () 16 | { 17 | this.buttons = new List (); 18 | 19 | this.SetFlag (WidgetFlags.NoWindow); 20 | 21 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 22 | } 23 | 24 | /// Adds a button before all existing buttons. 25 | /// The button to add. 26 | public void PrependButton (BaseButton Widget) 27 | { 28 | InsertButton (Widget, 0); 29 | } 30 | 31 | /// Adds a button after all existing buttons. 32 | /// The button to add. 33 | public void AppendButton (BaseButton Widget) 34 | { 35 | InsertButton (Widget, -1); 36 | } 37 | 38 | /// Inserts a button at the specified location. 39 | /// The button to add. 40 | /// The index (starting at 0) at which the button must be inserted, or -1 to insert the button after all existing buttons. 41 | public void InsertButton (BaseButton Widget, int ButtonIndex) 42 | { 43 | Widget.Parent = this; 44 | Widget.Visible = true; 45 | 46 | Widget.DrawBackground = true; 47 | 48 | if(ButtonIndex == -1 || ButtonIndex == buttons.Count) 49 | { 50 | if(buttons.Count == 0) 51 | { 52 | Widget.GroupStyle = GroupStyle.Alone; 53 | } 54 | else 55 | { 56 | Widget.GroupStyle = GroupStyle.Right; 57 | 58 | if(buttons.Count == 1) 59 | { 60 | buttons[buttons.Count - 1].GroupStyle = GroupStyle.Left; 61 | } 62 | else if(buttons.Count > 1) 63 | { 64 | buttons[buttons.Count - 1].GroupStyle = GroupStyle.Center; 65 | } 66 | } 67 | buttons.Add (Widget); 68 | } 69 | else 70 | { 71 | if(ButtonIndex == 0) 72 | { 73 | buttons[buttons.Count - 1].GroupStyle = GroupStyle.Left; 74 | if(buttons.Count == 1) 75 | { 76 | buttons[0].GroupStyle = GroupStyle.Right; 77 | } 78 | else 79 | { 80 | buttons[0].GroupStyle = GroupStyle.Center; 81 | } 82 | } 83 | buttons.Insert (ButtonIndex, Widget); 84 | } 85 | 86 | ShowAll (); 87 | } 88 | 89 | /// Removes the button at the specified index. 90 | /// Index of the button to remove. 91 | public void RemoveButton (int ButtonIndex) 92 | { 93 | buttons[ButtonIndex].Parent = null; 94 | 95 | if(ButtonIndex == 0) 96 | { 97 | if(buttons.Count > 1) 98 | { 99 | if(buttons.Count > 2) 100 | { 101 | buttons[0].GroupStyle = GroupStyle.Left; 102 | } 103 | else 104 | { 105 | buttons[0].GroupStyle = GroupStyle.Alone; 106 | } 107 | } 108 | } 109 | else if(ButtonIndex == buttons.Count - 1) 110 | { 111 | if(buttons.Count > 1) 112 | { 113 | if(buttons.Count > 2) 114 | { 115 | buttons[0].GroupStyle = GroupStyle.Right; 116 | } 117 | else 118 | { 119 | buttons[0].GroupStyle = GroupStyle.Alone; 120 | } 121 | } 122 | } 123 | buttons.RemoveAt (ButtonIndex); 124 | 125 | ShowAll (); 126 | } 127 | 128 | protected override void ForAll (bool include_internals, Callback callback) 129 | { 130 | foreach(BaseButton b in buttons) 131 | { 132 | if(b.Visible) callback (b); 133 | } 134 | } 135 | 136 | protected override void OnSizeRequested (ref Requisition requisition) 137 | { 138 | base.OnSizeRequested (ref requisition); 139 | 140 | if(widths == null || widths.Length != buttons.Count) 141 | { 142 | widths = new int[buttons.Count]; 143 | } 144 | 145 | requisition.Height = requisition.Width = 0; 146 | int i = 0; 147 | foreach(BaseButton b in buttons) 148 | { 149 | Gtk.Requisition req = b.SizeRequest (); 150 | if(requisition.Height < req.Height) requisition.Height = req.Height; 151 | requisition.Width += req.Width; 152 | widths[i++] = req.Width; 153 | } 154 | if(HeightRequest != -1) requisition.Height = HeightRequest; 155 | if(WidthRequest != -1) requisition.Width = WidthRequest; 156 | } 157 | 158 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 159 | { 160 | base.OnSizeAllocated (allocation); 161 | 162 | int i = 0, x = allocation.X; 163 | foreach(BaseButton b in buttons) 164 | { 165 | Gdk.Rectangle r; 166 | r.X = x; 167 | r.Y = allocation.Y; 168 | r.Width = widths[i]; 169 | r.Height = allocation.Height; 170 | b.SizeAllocate (r); 171 | x += r.Width; 172 | ++i; 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /Ribbons/VariantsCombinaison.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | // Note: this widget shall display a button at the left and the right 8 | // to scroll groups when the allocated with is not enough. 9 | 10 | /// 11 | /// A set of widgets displayed horizontaly. 12 | /// 13 | /// 14 | /// On the contrary of a classical container, the VariantsCombinaison is only 15 | /// the parent of its children if it has a parent itself. 16 | /// 17 | public class VariantsCombinaison : Container 18 | { 19 | private List widgets; 20 | private Button left, right; 21 | private Gtk.Requisition[] requisitions; 22 | private int spacing; 23 | 24 | public VariantsCombinaison () 25 | { 26 | Init (); 27 | } 28 | 29 | protected VariantsCombinaison (IntPtr raw) : base (raw) 30 | { 31 | Init (); 32 | } 33 | 34 | private void Init () 35 | { 36 | this.widgets = new List (); 37 | 38 | this.SetFlag (WidgetFlags.NoWindow); 39 | 40 | this.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 41 | 42 | this.spacing = 2; 43 | } 44 | 45 | /*public void Measure (int Height) 46 | { 47 | width = 0; 48 | foreach(Widget variant in variants) 49 | { 50 | variant.Measure (Height); 51 | width += variant.Width; 52 | } 53 | }*/ 54 | 55 | /// Gets or sets the spacing between children. 56 | public int Spacing 57 | { 58 | set 59 | { 60 | spacing = value; 61 | QueueDraw (); 62 | } 63 | get { return spacing; } 64 | } 65 | 66 | /// Adds a widget before all existing widgets. 67 | /// The widget to add. 68 | public void Prepend (Widget w) 69 | { 70 | Insert (w, 0); 71 | } 72 | 73 | /// Adds a widget after all existing widgets. 74 | /// The widget to add. 75 | public void Append (Widget w) 76 | { 77 | Insert (w, -1); 78 | } 79 | 80 | /// Inserts a widget at the specified location. 81 | /// The widget to add. 82 | /// The index (starting at 0) at which the widget must be inserted, or -1 to insert the widget after all existing widgets. 83 | public void Insert (Widget w, int WidgetIndex) 84 | { 85 | if(Parent != null) w.Parent = this; 86 | w.Visible = true; 87 | 88 | if(WidgetIndex == -1) 89 | widgets.Add (w); 90 | else 91 | widgets.Insert (WidgetIndex, w); 92 | 93 | ShowAll (); 94 | } 95 | 96 | /// Removes the widget at the specified index. 97 | /// Index of the widget to remove. 98 | public void Remove (int WidgetIndex) 99 | { 100 | if(Parent != null) widgets[WidgetIndex].Parent = null; 101 | 102 | if(WidgetIndex == -1) 103 | widgets.RemoveAt (widgets.Count - 1); 104 | else 105 | widgets.RemoveAt (WidgetIndex); 106 | 107 | ShowAll (); 108 | } 109 | 110 | protected override void OnParentSet (Widget previous_parent) 111 | { 112 | base.OnParentSet (previous_parent); 113 | 114 | if(Parent == null) 115 | {Console.WriteLine ("unparnet"); 116 | foreach(Widget w in widgets) w.Unparent (); 117 | } 118 | else 119 | {Console.WriteLine ("ok"); 120 | foreach(Widget w in widgets) w.Parent = this; 121 | } 122 | } 123 | 124 | protected override void ForAll (bool include_internals, Callback callback) 125 | { 126 | //if(Parent == null) return; 127 | 128 | foreach(Widget w in widgets) 129 | { 130 | if(w.Visible) callback (w); 131 | } 132 | } 133 | 134 | protected override void OnSizeRequested (ref Requisition requisition) 135 | { 136 | base.OnSizeRequested (ref requisition); 137 | 138 | if(requisitions == null || requisitions.Length != widgets.Count) 139 | { 140 | requisitions = new Gtk.Requisition[widgets.Count]; 141 | } 142 | 143 | int totalWidth = 0, rowHeight = 0; 144 | if(HeightRequest == -1) 145 | { 146 | foreach(Widget w in widgets) 147 | { 148 | if(w.Visible) 149 | { 150 | rowHeight = Math.Max (rowHeight, w.SizeRequest ().Height); 151 | } 152 | } 153 | } 154 | else rowHeight = HeightRequest - 2*(int)BorderWidth; 155 | 156 | int i = 0; 157 | foreach(Widget w in widgets) 158 | { 159 | if(w.Visible) 160 | { 161 | w.HeightRequest = rowHeight; 162 | requisitions[i] = w.SizeRequest (); 163 | totalWidth += requisitions[i].Width + spacing; 164 | } 165 | ++i; 166 | } 167 | totalWidth -= spacing; 168 | 169 | requisition.Height = rowHeight; 170 | if(WidthRequest != -1) 171 | requisition.Width = WidthRequest; 172 | else 173 | requisition.Width = totalWidth; 174 | } 175 | 176 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 177 | { 178 | base.OnSizeAllocated (allocation); 179 | 180 | int right = allocation.X + allocation.Width - (int)BorderWidth; 181 | int left = allocation.X + (int)BorderWidth; 182 | int bottom = allocation.Y + allocation.Height - (int)BorderWidth; 183 | int x = left, y = allocation.Y + (int)BorderWidth; 184 | 185 | int i = 0; 186 | foreach(Widget w in widgets) 187 | { 188 | if(w.Visible) 189 | { 190 | Gdk.Rectangle r; 191 | r.X = x; 192 | r.Y = y; 193 | r.Width = Math.Min (right, r.X + requisitions[i].Width) - r.X; 194 | //r.Height = Math.Min (bottom, r.Y + requisitions[i].Height) - r.Y; 195 | r.Height = bottom - y; 196 | w.SizeAllocate (r); 197 | 198 | x += r.Width + spacing; 199 | } 200 | ++i; 201 | } 202 | } 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /Ribbons/VariantsCombinaisonSwitcher.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Gtk; 4 | 5 | namespace Ribbons 6 | { 7 | /// 8 | /// Selects a certain VariantsCombinaison based on space constraints. 9 | /// 10 | public class VariantsCombinaisonSwitcher : Container 11 | { 12 | private List combinaisons; 13 | private int requestedWidth, requiredHeight; 14 | private VariantsCombinaison candidateCombinaison; 15 | private VariantsCombinaison selectedCombinaison; 16 | 17 | public int Count 18 | { 19 | get { return combinaisons.Count; } 20 | } 21 | 22 | public VariantsCombinaison this[int Index] 23 | { 24 | get { return combinaisons[Index]; } 25 | } 26 | 27 | public VariantsCombinaisonSwitcher () 28 | { 29 | Init (); 30 | } 31 | 32 | protected VariantsCombinaisonSwitcher (IntPtr raw) : base (raw) 33 | { 34 | Init (); 35 | } 36 | 37 | private void Init () 38 | { 39 | combinaisons = new List (); 40 | 41 | SetFlag (WidgetFlags.NoWindow); 42 | 43 | AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 44 | } 45 | 46 | public void AddCombinaison (VariantsCombinaison Combinaison) 47 | { 48 | combinaisons.Add (Combinaison); 49 | } 50 | 51 | public void RemoveCombinaison (VariantsCombinaison Combinaison) 52 | { 53 | combinaisons.Remove (Combinaison); 54 | } 55 | 56 | public void RemoveCombinaisonAt (int Index) 57 | { 58 | combinaisons.RemoveAt (Index); 59 | } 60 | 61 | protected override void ForAll (bool include_internals, Callback callback) 62 | { 63 | if(selectedCombinaison != null) callback (selectedCombinaison); 64 | } 65 | int counter = 0; 66 | protected override void OnSizeRequested (ref Requisition requisition) 67 | { 68 | Console.WriteLine ("TEST"); 69 | base.OnSizeRequested (ref requisition); 70 | 71 | /*combinaisons[0].HeightRequest = HeightRequest; 72 | requisition = combinaisons[0].SizeRequest (); 73 | requiredHeight = requisition.Height; 74 | requestedWidth = requisition.Width; 75 | candidateCombinaison = combinaisons[0]; 76 | return;*/ 77 | 78 | candidateCombinaison = null; 79 | requiredHeight = HeightRequest; 80 | 81 | if(WidthRequest == -1) 82 | { 83 | int width = int.MaxValue; 84 | 85 | foreach(VariantsCombinaison combi in combinaisons) 86 | { 87 | //combi.HeightRequest = HeightRequest; 88 | 89 | Requisition req = combi.SizeRequest (); 90 | 91 | if(req.Width < width) 92 | { 93 | candidateCombinaison = combi; 94 | width = req.Width; 95 | requiredHeight = req.Height; 96 | } 97 | } 98 | 99 | requestedWidth = requisition.Width = width; 100 | } 101 | else if(HeightRequest == -1) 102 | { 103 | int width = -1; 104 | 105 | foreach(VariantsCombinaison combi in combinaisons) 106 | { 107 | combi.HeightRequest = -1; 108 | 109 | Requisition req = combi.SizeRequest (); 110 | 111 | if((req.Width <= WidthRequest && req.Width > width) || (width > WidthRequest && req.Width < width)) 112 | { 113 | candidateCombinaison = combi; 114 | width = req.Width; 115 | requiredHeight = req.Height; 116 | } 117 | } 118 | 119 | requestedWidth = requisition.Width = WidthRequest; 120 | } 121 | 122 | if(HeightRequest == -1) requisition.Height = requiredHeight; 123 | else requisition.Height = HeightRequest; 124 | 125 | Console.WriteLine ("Switcher req: " + requisition.Width + " " + requisition.Height); 126 | } 127 | 128 | protected override void OnSizeAllocated (Gdk.Rectangle allocation) 129 | {Console.WriteLine (allocation.Width + " " + allocation.Height); 130 | base.OnSizeAllocated (allocation); 131 | 132 | if(requestedWidth != allocation.Width || requiredHeight != allocation.Height) 133 | { 134 | int width = -1; 135 | candidateCombinaison = null; 136 | 137 | foreach(VariantsCombinaison combi in combinaisons) 138 | { 139 | //combi.HeightRequest = allocation.Height; 140 | 141 | Requisition req = combi.SizeRequest (); 142 | 143 | if(req.Width <= allocation.Width && req.Width > width) 144 | { 145 | candidateCombinaison = combi; 146 | width = req.Width; 147 | } 148 | } 149 | } 150 | 151 | Select (candidateCombinaison); 152 | 153 | if(candidateCombinaison != null) 154 | { 155 | candidateCombinaison.SizeAllocate (allocation); 156 | } 157 | } 158 | 159 | private void Select (VariantsCombinaison combi) 160 | {Console.WriteLine ("Select: " + combi); 161 | if(selectedCombinaison != combi) 162 | { 163 | if(selectedCombinaison != null) 164 | { 165 | selectedCombinaison.Unparent (); 166 | } 167 | 168 | if(combi != null) 169 | { 170 | combi.Parent = this; 171 | } 172 | 173 | selectedCombinaison = combi; 174 | } 175 | } 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Ribbons/gtk-gui/generated.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Mono Runtime Version: 2.0.50727.42 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | // ------------------------------------------------------------------------------ 10 | 11 | namespace Stetic { 12 | 13 | 14 | internal class Gui { 15 | 16 | private static bool initialized; 17 | 18 | internal static void Initialize(Gtk.Widget iconRenderer) { 19 | if ((Stetic.Gui.initialized == false)) { 20 | Stetic.Gui.initialized = true; 21 | } 22 | } 23 | } 24 | 25 | internal class ActionGroups { 26 | 27 | public static Gtk.ActionGroup GetActionGroup(System.Type type) { 28 | return Stetic.ActionGroups.GetActionGroup(type.FullName); 29 | } 30 | 31 | public static Gtk.ActionGroup GetActionGroup(string name) { 32 | return null; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Ribbons/gtk-gui/gui.stetic: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Ribbons/gtk-gui/objects.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Sample/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | 4 | // Information about this assembly is defined by the following 5 | // attributes. 6 | // 7 | // change them to the information which is associated with the assembly 8 | // you compile. 9 | 10 | [assembly: AssemblyTitle("")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("")] 15 | [assembly: AssemblyCopyright("")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // The assembly version has following format : 20 | // 21 | // Major.Minor.Build.Revision 22 | // 23 | // You can specify all values by your own or you can build default build and revision 24 | // numbers with the '*' character (the default): 25 | 26 | [assembly: AssemblyVersion("1.0.*")] 27 | 28 | // The following attributes specify the key for the sign of your assembly. See the 29 | // .NET Framework documentation for more information about signing. 30 | // This is not required, if you don't want signing let these attributes like they're. 31 | [assembly: AssemblyDelaySign(false)] 32 | [assembly: AssemblyKeyFile("")] 33 | -------------------------------------------------------------------------------- /Sample/ChangeLog: -------------------------------------------------------------------------------- 1 | 2008-08-18 Laurent Debacker 2 | 3 | * MainWindow.cs: Updated sample for key tips. 4 | 5 | 2008-08-15 Laurent Debacker 6 | 7 | * MainWindow.cs: Updated the main sample to integrate the sample developed 8 | in VariantsCombinaisonTest 9 | 10 | 2008-08-11 Laurent Debacker 11 | 12 | * DropdownGroupTest.cs: New test for drop down ribbon groups 13 | * VariantsCombinaisonTest.cs: New test for variants combinaisons 14 | 15 | 2008-07-11 Laurent Debacker 16 | 17 | * MainWindow.cs: Updated sample to show menu opening in app menu 18 | 19 | 2008-07-11 Laurent Debacker 20 | 21 | * MainWindow.cs: Update sample to showcase advance in app menu 22 | implementation 23 | 24 | 2008-07-07 Laurent Debacker 25 | 26 | * MainWindow.cs: Update sample 27 | 28 | 2008-06-30 Laurent Debacker 29 | 30 | * Sample/MainWindow.cs: Updated sample 31 | * Ribbons/Theme.cs: Quick Access Toolbar background 32 | * Ribbons/ApplicationMenu.cs: Initial stub API for application menu. 33 | * Ribbons/QuickAccessToolbar.cs: Take care of height requests from 34 | children widgets 35 | 36 | 2007-12-29 Laurent Debacker 37 | 38 | 39 | 40 | 2007-12-28 Laurent Debacker 41 | 42 | * MainWindow.cs, ChangeLog: Fixing calls to Dispose() and Destroy() 43 | 44 | -------------------------------------------------------------------------------- /Sample/DropdownGroupTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | using Ribbons; 5 | 6 | namespace Sample 7 | { 8 | public class DropdownGroupTest : SyntheticWindow 9 | { 10 | protected bool composeAvailable = false; 11 | 12 | protected Label pageLabel1; 13 | 14 | public DropdownGroupTest() : base (WindowType.Toplevel) 15 | { 16 | AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 17 | 18 | HBox master = new HBox (); 19 | master.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 20 | 21 | Title = "Ribbons Sample"; 22 | AppPaintable = true; 23 | 24 | Ribbons.Button button0 = new Ribbons.Button ("Hello World"); 25 | 26 | RibbonGroup group0 = new RibbonGroup (); 27 | group0.Label = "Summer of Code"; 28 | group0.Child = button0; 29 | group0.Expand += onClick; 30 | 31 | DropdownRibbonGroup dropGroup0 = new DropdownRibbonGroup (); 32 | dropGroup0.Group = group0; 33 | dropGroup0.Label = "Drop 1"; 34 | 35 | DropdownRibbonGroup dropGroup1 = new DropdownRibbonGroup (); 36 | dropGroup1.Group = group0; 37 | dropGroup1.Label = "Drop 2"; 38 | 39 | master.PackStart (dropGroup0, false, false, 0); 40 | master.PackStart (dropGroup1, false, false, 0); 41 | 42 | Add (master); 43 | 44 | ScreenChanged += Window_OnScreenChanged; 45 | Window_OnScreenChanged (this, null); 46 | ExposeEvent += Window_OnExpose; 47 | DeleteEvent += Window_OnDelete; 48 | 49 | this.Resize (200, 200); 50 | this.ShowAll (); 51 | } 52 | 53 | private void onClick (object Sender, EventArgs e) 54 | { 55 | Dialog d = new Dialog ("Test", this, DialogFlags.DestroyWithParent); 56 | d.Modal = true; 57 | d.AddButton ("Close", ResponseType.Close); 58 | d.Run (); 59 | d.Destroy (); 60 | } 61 | 62 | [GLib.ConnectBefore] 63 | private void Window_OnExpose (object sender, ExposeEventArgs args) 64 | { 65 | Gdk.EventExpose evnt = args.Event; 66 | Context cr = Gdk.CairoHelper.Create (GdkWindow); 67 | 68 | /*if(composeAvailable) 69 | cr.SetSourceRGBA (0, 0, 0, 0.3); 70 | else*/ 71 | cr.SetSourceRGB (0.3, 0.3, 0.3); 72 | 73 | //cr.SetSourceRGB (0.749, 0.859, 1.0); 74 | 75 | cr.Operator = Operator.Source; 76 | cr.Paint (); 77 | 78 | ((IDisposable)cr.Target).Dispose(); 79 | ((IDisposable)cr).Dispose(); 80 | 81 | args.RetVal = false; 82 | } 83 | 84 | private void Window_OnScreenChanged (object Send, ScreenChangedArgs args) 85 | { 86 | Gdk.Colormap cm = Screen.RgbaColormap; 87 | composeAvailable = cm != null; // FIX: Do not seem to detect compose support in all cases 88 | 89 | if(!composeAvailable) cm = Screen.RgbColormap; 90 | Colormap = cm; 91 | 92 | Console.WriteLine ("Compose Support: " + composeAvailable); 93 | } 94 | 95 | private void Window_OnDelete (object send, DeleteEventArgs args) 96 | { 97 | Application.Quit (); 98 | args.RetVal = true; 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Sample/Main.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Gtk; 3 | 4 | namespace Sample 5 | { 6 | class MainClass 7 | { 8 | public static void Main(string[] args) 9 | { 10 | Console.WriteLine ("Starting ..."); 11 | Application.Init (); 12 | MainWindow win = new MainWindow (); 13 | //VariantsCombinaisonTest win = new VariantsCombinaisonTest (); 14 | win.Show (); 15 | Application.Run (); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Sample/MainWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | using Ribbons; 5 | 6 | namespace Sample 7 | { 8 | public class MainWindow : SyntheticWindow 9 | { 10 | protected bool composeAvailable = false; 11 | 12 | protected Ribbon ribbon; 13 | protected RibbonGroup group0, group1, group2; 14 | 15 | protected Label pageLabel1; 16 | 17 | public MainWindow() : base (WindowType.Toplevel) 18 | { 19 | AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 20 | 21 | VBox master = new VBox (); 22 | master.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 23 | 24 | Title = "Ribbons Sample"; 25 | AppPaintable = true; 26 | 27 | VariantsCombinaisonSwitcher page0 = new VariantsCombinaisonSwitcher (); 28 | 29 | RibbonGroup group0 = CreateGroup0 (); 30 | RibbonGroup group1 = CreateGroup1 (); 31 | RibbonGroup group2 = CreateGroup2 (); 32 | DropdownRibbonGroup dgroup0 = CreateDropdownGroup0 (); 33 | dgroup0.Group = group0; 34 | DropdownRibbonGroup dgroup1 = CreateDropdownGroup1 (); 35 | dgroup1.Group = group1; 36 | DropdownRibbonGroup dgroup2 = CreateDropdownGroup2 (); 37 | dgroup2.Group = group2; 38 | 39 | VariantsCombinaison combi0 = new VariantsCombinaison (); 40 | combi0.Append (group0); 41 | combi0.Append (group1); 42 | combi0.Append (group2); 43 | page0.AddCombinaison (combi0); 44 | 45 | VariantsCombinaison combi1 = new VariantsCombinaison (); 46 | combi1.Append (group0); 47 | combi1.Append (group1); 48 | combi1.Append (dgroup2); 49 | page0.AddCombinaison (combi1); 50 | 51 | VariantsCombinaison combi2 = new VariantsCombinaison (); 52 | combi2.Append (dgroup0); 53 | combi2.Append (dgroup1); 54 | combi2.Append (dgroup2); 55 | page0.AddCombinaison (combi2); 56 | 57 | HBox page1 = new HBox (false, 2); 58 | RibbonGroup group10 = new RibbonGroup (); 59 | group10.Label = "Welcome on the second page"; 60 | page1.PackStart (group10, false, false, 0); 61 | 62 | HBox page2 = new HBox (false, 2); 63 | 64 | Label pageLabel0 = new Label ("Page 1"); 65 | pageLabel1 = new Label ("Page 2"); 66 | Label pageLabel2 = new Label ("Page 3"); 67 | 68 | Ribbons.Button shortcuts = new Ribbons.Button ("Menu"); 69 | shortcuts.Child.ModifyFg (Gtk.StateType.Normal, new Gdk.Color(255, 255, 255)); 70 | 71 | Menu mainMenu = new Menu (); 72 | MenuItem mainMenu_quit = new MenuItem ("Quit"); 73 | mainMenu_quit.Activated += delegate (object Sender, EventArgs e) 74 | { 75 | Application.Quit (); 76 | }; 77 | mainMenu.Append (mainMenu_quit); 78 | 79 | shortcuts.Clicked += delegate (object Sender, EventArgs e) 80 | { 81 | mainMenu.Popup (); 82 | mainMenu.ShowAll (); 83 | }; 84 | 85 | QuickAccessToolbar qat = new QuickAccessToolbar (); 86 | Ribbons.Button qatNew, qatSave; 87 | qat.Append (qatNew = Ribbons.Button.FromStockIcon (Gtk.Stock.New, false)); 88 | qat.Append (qatSave = Ribbons.Button.FromStockIcon (Gtk.Stock.Save, false)); 89 | 90 | ribbon = new Ribbon (); 91 | ribbon.ApplicationButton = new ApplicationButton (); 92 | ribbon.QuickAccessToolbar = qat; 93 | //ribbon.Shortcuts = shortcuts; 94 | ribbon.AppendPage (page0, pageLabel0); 95 | ribbon.AppendPage (page1, pageLabel1); 96 | ribbon.AppendPage (page2, pageLabel2); 97 | pageLabel1.AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 98 | pageLabel1.ButtonPressEvent += delegate (object sender, ButtonPressEventArgs e) 99 | { 100 | Console.WriteLine("label1 press"); 101 | }; 102 | pageLabel1.EnterNotifyEvent += delegate (object sender, EnterNotifyEventArgs e) 103 | { 104 | Console.WriteLine("label1 enter"); 105 | }; 106 | pageLabel1.LeaveNotifyEvent += delegate (object sender, LeaveNotifyEventArgs e) 107 | { 108 | Console.WriteLine("label1 leave"); 109 | }; 110 | 111 | ApplicationMenu appMenu = ribbon.ApplicationButton.Menu; 112 | TextView mnu = new TextView (); 113 | appMenu.DefaultMenu = mnu; 114 | mnu.Buffer.InsertAtCursor ("Default"); 115 | ApplicationMenuItem mi = new ApplicationMenuItem ("Test 1"); 116 | mnu = new TextView (); 117 | mi.Menu = mnu; 118 | mnu.Buffer.InsertAtCursor ("Test 1"); 119 | appMenu.Append (mi); 120 | mi = new ApplicationMenuItem ("Test 2"); 121 | appMenu.Append (mi); 122 | mi = new ApplicationMenuItem ("Test 3"); 123 | appMenu.Append (mi); 124 | 125 | appMenu.OptionsButton = new Ribbons.Button ("Options"); 126 | appMenu.ExitButton = new Ribbons.Button ("Exit"); 127 | 128 | TextView txt = new TextView (); 129 | 130 | master.PackStart (ribbon, false, false, 0); 131 | master.PackStart (txt, true, true, 0); 132 | 133 | Add (master); 134 | 135 | ribbon.ApplicationButton.KeyTip = new KeyTip (appMenu, "A"); 136 | qat.AddKeyTip (new KeyTip (qatNew, "B")); 137 | qat.AddKeyTip (new KeyTip (qatSave, "C")); 138 | ribbon.AddTabKeyTip (new KeyTip (pageLabel0, "D")); 139 | ribbon.AddTabKeyTip (new KeyTip (pageLabel1, "E")); 140 | ribbon.AddTabKeyTip (new KeyTip (pageLabel2, "F")); 141 | 142 | ScreenChanged += Window_OnScreenChanged; 143 | Window_OnScreenChanged (this, null); 144 | ExposeEvent += Window_OnExpose; 145 | DeleteEvent += Window_OnDelete; 146 | 147 | this.Resize (200, 200); 148 | this.ShowAll (); 149 | } 150 | 151 | private RibbonGroup CreateGroup0 () 152 | { 153 | Ribbons.Button button0 = new Ribbons.Button ("Hello World"); 154 | 155 | RibbonGroup group0 = new RibbonGroup (); 156 | group0.Label = "Summer of Code"; 157 | group0.Child = button0; 158 | group0.Expand += onClick; 159 | 160 | return group0; 161 | } 162 | 163 | private DropdownRibbonGroup CreateDropdownGroup0 () 164 | { 165 | DropdownRibbonGroup ret = new DropdownRibbonGroup (); 166 | ret.Label = "Summer of Code"; 167 | return ret; 168 | } 169 | 170 | private RibbonGroup CreateGroup1 () 171 | { 172 | Ribbons.Button button1 = new Ribbons.Button ("Menu Test"); 173 | button1.Clicked += onClick; 174 | Menu button1_menu = new Menu (); 175 | MenuItem option1 = new MenuItem ("Option 1"); 176 | button1_menu.Append (option1); 177 | button1.DropDownMenu = button1_menu; 178 | 179 | Menu openMenu = new Menu (); 180 | MenuItem abc_txt = new MenuItem ("abc.txt"); 181 | openMenu.Append (abc_txt); 182 | MenuItem foo_txt = new MenuItem ("foo.txt"); 183 | openMenu.Append (foo_txt); 184 | 185 | Ribbons.Button open = Ribbons.Button.FromStockIcon (Gtk.Stock.Open, "Open", false); 186 | open.DropDownMenu = openMenu; 187 | open.Clicked += onClick; 188 | 189 | Ribbons.ToolPack fileToolPack = new Ribbons.ToolPack (); 190 | fileToolPack.AppendButton (Ribbons.Button.FromStockIcon (Gtk.Stock.New, "New", false)); 191 | fileToolPack.AppendButton (open); 192 | fileToolPack.AppendButton (Ribbons.Button.FromStockIcon (Gtk.Stock.Save, "Save", false)); 193 | 194 | Ribbons.ToolPack printerToolPack = new Ribbons.ToolPack (); 195 | printerToolPack.AppendButton (Ribbons.Button.FromStockIcon (Gtk.Stock.Print, "Print", false)); 196 | 197 | Ribbons.ToolPack fontToolPack = new Ribbons.ToolPack (); 198 | fontToolPack.AppendButton (Ribbons.ToggleButton.FromStockIcon (Gtk.Stock.Bold, false)); 199 | fontToolPack.AppendButton (Ribbons.ToggleButton.FromStockIcon (Gtk.Stock.Italic, false)); 200 | fontToolPack.AppendButton (Ribbons.ToggleButton.FromStockIcon (Gtk.Stock.Underline, false)); 201 | 202 | ComboBox font = new ComboBox (new string[] { "Arial", "Verdana" }); 203 | font.Active = 0; 204 | 205 | Ribbons.ToolBox flow0 = new ToolBox (); 206 | flow0.Append (fileToolPack); 207 | flow0.Append (printerToolPack); 208 | flow0.Append (fontToolPack); 209 | flow0.Append (font); 210 | 211 | HBox btnFlowBox = new HBox (false, 2); 212 | btnFlowBox.Add (button1); 213 | btnFlowBox.Add (flow0); 214 | 215 | // Little hack because Gtk+ is not designed to support size negociations 216 | btnFlowBox.SizeAllocated += delegate(object Sender, SizeAllocatedArgs e) 217 | { 218 | flow0.HeightRequest = e.Allocation.Height; 219 | }; 220 | 221 | RibbonGroup group1 = new RibbonGroup (); 222 | group1.Label = "I will be back"; 223 | group1.Child = btnFlowBox; 224 | 225 | return group1; 226 | } 227 | 228 | private DropdownRibbonGroup CreateDropdownGroup1 () 229 | { 230 | DropdownRibbonGroup ret = new DropdownRibbonGroup (); 231 | ret.Label = "I will be back"; 232 | return ret; 233 | } 234 | 235 | private RibbonGroup CreateGroup2 () 236 | { 237 | Gallery gallery = new Gallery (); 238 | gallery.AppendTile (new SampleTile ("1")); 239 | gallery.AppendTile (new SampleTile ("2")); 240 | gallery.AppendTile (new SampleTile ("3")); 241 | gallery.AppendTile (new SampleTile ("4")); 242 | gallery.AppendTile (new SampleTile ("5")); 243 | 244 | RibbonGroup group2 = new RibbonGroup (); 245 | group2.Label = "Gallery"; 246 | group2.Child = gallery; 247 | 248 | return group2; 249 | } 250 | 251 | private DropdownRibbonGroup CreateDropdownGroup2 () 252 | { 253 | DropdownRibbonGroup ret = new DropdownRibbonGroup (); 254 | ret.Label = "Gallery"; 255 | return ret; 256 | } 257 | 258 | private void onClick (object Sender, EventArgs e) 259 | { 260 | Dialog d = new Dialog ("Test", this, DialogFlags.DestroyWithParent); 261 | d.Modal = true; 262 | d.AddButton ("Close", ResponseType.Close); 263 | d.Run (); 264 | d.Destroy (); 265 | } 266 | 267 | protected override bool OnKeyPressEvent (Gdk.EventKey evnt) 268 | { 269 | if(evnt.Key.ToString() == "Alt_L" || evnt.Key.ToString() == "ISO_Level3_Shift") 270 | { 271 | ribbon.ShowTopLevelKeyTips (); 272 | } 273 | 274 | return base.OnKeyPressEvent (evnt); 275 | } 276 | 277 | protected override bool OnKeyReleaseEvent (Gdk.EventKey evnt) 278 | { 279 | if(evnt.Key.ToString() == "Alt_L" || evnt.Key.ToString() == "ISO_Level3_Shift") 280 | { 281 | ribbon.HideKeyTips (); 282 | } 283 | 284 | return base.OnKeyReleaseEvent (evnt); 285 | } 286 | 287 | [GLib.ConnectBefore] 288 | private void Window_OnExpose (object sender, ExposeEventArgs args) 289 | { 290 | Gdk.EventExpose evnt = args.Event; 291 | Context cr = Gdk.CairoHelper.Create (GdkWindow); 292 | 293 | /*if(composeAvailable) 294 | cr.SetSourceRGBA (0, 0, 0, 0.3); 295 | else*/ 296 | cr.SetSourceRGB (0.3, 0.3, 0.3); 297 | 298 | //cr.SetSourceRGB (0.749, 0.859, 1.0); 299 | 300 | cr.Operator = Operator.Source; 301 | cr.Paint (); 302 | 303 | ((IDisposable)cr.Target).Dispose(); 304 | ((IDisposable)cr).Dispose(); 305 | 306 | args.RetVal = false; 307 | } 308 | 309 | private void Window_OnScreenChanged (object Send, ScreenChangedArgs args) 310 | { 311 | Gdk.Colormap cm = Screen.RgbaColormap; 312 | composeAvailable = cm != null; // FIX: Do not seem to detect compose support in all cases 313 | 314 | if(!composeAvailable) cm = Screen.RgbColormap; 315 | Colormap = cm; 316 | 317 | Console.WriteLine ("Compose Support: " + composeAvailable); 318 | } 319 | 320 | private void Window_OnDelete (object send, DeleteEventArgs args) 321 | { 322 | Application.Quit (); 323 | args.RetVal = true; 324 | } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /Sample/Sample.mdp: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Sample/SampleTile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Ribbons; 4 | 5 | namespace Sample 6 | { 7 | public class SampleTile : Tile 8 | { 9 | private string txt; 10 | private Pango.Layout textLayout; 11 | 12 | public SampleTile (string Text) 13 | { 14 | txt = Text; 15 | textLayout = CreatePangoLayout (Text); 16 | } 17 | 18 | public override Tile Copy () 19 | { 20 | return new SampleTile (txt); 21 | } 22 | 23 | public override void DrawContent (Cairo.Context Context, Cairo.Rectangle Area) 24 | { 25 | Context.Color = new Color (0, 0, 0); 26 | Pango.CairoHelper.UpdateLayout (Context, textLayout); 27 | Context.MoveTo (Area.X, Area.Y); 28 | Pango.CairoHelper.ShowLayout (Context, textLayout); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sample/VariantsCombinaisonTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Cairo; 3 | using Gtk; 4 | using Ribbons; 5 | 6 | namespace Sample 7 | { 8 | public class VariantsCombinaisonTest : SyntheticWindow 9 | { 10 | protected bool composeAvailable = false; 11 | 12 | protected Label pageLabel1; 13 | 14 | public VariantsCombinaisonTest() : base (WindowType.Toplevel) 15 | { 16 | AddEvents ((int)(Gdk.EventMask.ButtonPressMask | Gdk.EventMask.ButtonReleaseMask | Gdk.EventMask.PointerMotionMask)); 17 | Title = "Ribbons Sample"; 18 | AppPaintable = true; 19 | 20 | VariantsCombinaisonSwitcher switcher = new VariantsCombinaisonSwitcher (); 21 | 22 | RibbonGroup group0 = CreateGroup0 (); 23 | RibbonGroup group1 = CreateGroup1 (); 24 | RibbonGroup group2 = CreateGroup2 (); 25 | DropdownRibbonGroup dgroup0 = CreateDropdownGroup0 (); 26 | dgroup0.Group = group0; 27 | DropdownRibbonGroup dgroup1 = CreateDropdownGroup1 (); 28 | dgroup1.Group = group1; 29 | DropdownRibbonGroup dgroup2 = CreateDropdownGroup2 (); 30 | dgroup2.Group = group2; 31 | 32 | VariantsCombinaison combi0 = new VariantsCombinaison (); 33 | combi0.Append (group0); 34 | combi0.Append (group1); 35 | combi0.Append (group2); 36 | switcher.AddCombinaison (combi0); 37 | 38 | VariantsCombinaison combi1 = new VariantsCombinaison (); 39 | combi1.Append (group0); 40 | combi1.Append (group1); 41 | combi1.Append (dgroup2); 42 | switcher.AddCombinaison (combi1); 43 | 44 | VariantsCombinaison combi2 = new VariantsCombinaison (); 45 | combi2.Append (dgroup0); 46 | combi2.Append (dgroup1); 47 | combi2.Append (dgroup2); 48 | switcher.AddCombinaison (combi2); 49 | 50 | Add (switcher); 51 | 52 | ScreenChanged += Window_OnScreenChanged; 53 | Window_OnScreenChanged (this, null); 54 | ExposeEvent += Window_OnExpose; 55 | DeleteEvent += Window_OnDelete; 56 | 57 | this.Resize (200, 200); 58 | this.ShowAll (); 59 | } 60 | 61 | private RibbonGroup CreateGroup0 () 62 | { 63 | Ribbons.Button button0 = new Ribbons.Button ("Hello World"); 64 | 65 | RibbonGroup group0 = new RibbonGroup (); 66 | group0.Label = "Summer of Code"; 67 | group0.Child = button0; 68 | group0.Expand += onClick; 69 | 70 | return group0; 71 | } 72 | 73 | private DropdownRibbonGroup CreateDropdownGroup0 () 74 | { 75 | DropdownRibbonGroup ret = new DropdownRibbonGroup (); 76 | ret.Label = "Summer of Code"; 77 | return ret; 78 | } 79 | 80 | private RibbonGroup CreateGroup1 () 81 | { 82 | Ribbons.Button button1 = new Ribbons.Button ("Menu Test"); 83 | button1.Clicked += onClick; 84 | Menu button1_menu = new Menu (); 85 | MenuItem option1 = new MenuItem ("Option 1"); 86 | button1_menu.Append (option1); 87 | button1.DropDownMenu = button1_menu; 88 | 89 | Menu openMenu = new Menu (); 90 | MenuItem abc_txt = new MenuItem ("abc.txt"); 91 | openMenu.Append (abc_txt); 92 | MenuItem foo_txt = new MenuItem ("foo.txt"); 93 | openMenu.Append (foo_txt); 94 | 95 | Ribbons.Button open = Ribbons.Button.FromStockIcon (Gtk.Stock.Open, "Open", false); 96 | open.DropDownMenu = openMenu; 97 | open.Clicked += onClick; 98 | 99 | Ribbons.ToolPack fileToolPack = new Ribbons.ToolPack (); 100 | fileToolPack.AppendButton (Ribbons.Button.FromStockIcon (Gtk.Stock.New, "New", false)); 101 | fileToolPack.AppendButton (open); 102 | fileToolPack.AppendButton (Ribbons.Button.FromStockIcon (Gtk.Stock.Save, "Save", false)); 103 | 104 | Ribbons.ToolPack printerToolPack = new Ribbons.ToolPack (); 105 | printerToolPack.AppendButton (Ribbons.Button.FromStockIcon (Gtk.Stock.Print, "Print", false)); 106 | 107 | Ribbons.ToolPack fontToolPack = new Ribbons.ToolPack (); 108 | fontToolPack.AppendButton (Ribbons.ToggleButton.FromStockIcon (Gtk.Stock.Bold, false)); 109 | fontToolPack.AppendButton (Ribbons.ToggleButton.FromStockIcon (Gtk.Stock.Italic, false)); 110 | fontToolPack.AppendButton (Ribbons.ToggleButton.FromStockIcon (Gtk.Stock.Underline, false)); 111 | 112 | ComboBox font = new ComboBox (new string[] { "Arial", "Verdana" }); 113 | font.Active = 0; 114 | 115 | Ribbons.ToolBox flow0 = new ToolBox (); 116 | flow0.Append (fileToolPack); 117 | flow0.Append (printerToolPack); 118 | flow0.Append (fontToolPack); 119 | flow0.Append (font); 120 | 121 | HBox btnFlowBox = new HBox (false, 2); 122 | btnFlowBox.Add (button1); 123 | btnFlowBox.Add (flow0); 124 | 125 | // Little hack because Gtk+ is not designed to support size negociations 126 | btnFlowBox.SizeAllocated += delegate(object Sender, SizeAllocatedArgs e) 127 | { 128 | flow0.HeightRequest = e.Allocation.Height; 129 | }; 130 | 131 | RibbonGroup group1 = new RibbonGroup (); 132 | group1.Label = "I will be back"; 133 | group1.Child = btnFlowBox; 134 | 135 | return group1; 136 | } 137 | 138 | private DropdownRibbonGroup CreateDropdownGroup1 () 139 | { 140 | DropdownRibbonGroup ret = new DropdownRibbonGroup (); 141 | ret.Label = "I will be back"; 142 | return ret; 143 | } 144 | 145 | private RibbonGroup CreateGroup2 () 146 | { 147 | Gallery gallery = new Gallery (); 148 | gallery.AppendTile (new SampleTile ("1")); 149 | gallery.AppendTile (new SampleTile ("2")); 150 | gallery.AppendTile (new SampleTile ("3")); 151 | gallery.AppendTile (new SampleTile ("4")); 152 | gallery.AppendTile (new SampleTile ("5")); 153 | 154 | RibbonGroup group2 = new RibbonGroup (); 155 | group2.Label = "Gallery"; 156 | group2.Child = gallery; 157 | 158 | return group2; 159 | } 160 | 161 | private DropdownRibbonGroup CreateDropdownGroup2 () 162 | { 163 | DropdownRibbonGroup ret = new DropdownRibbonGroup (); 164 | ret.Label = "Gallery"; 165 | return ret; 166 | } 167 | 168 | private void onClick (object Sender, EventArgs e) 169 | { 170 | Dialog d = new Dialog ("Test", this, DialogFlags.DestroyWithParent); 171 | d.Modal = true; 172 | d.AddButton ("Close", ResponseType.Close); 173 | d.Run (); 174 | d.Destroy (); 175 | } 176 | 177 | [GLib.ConnectBefore] 178 | private void Window_OnExpose (object sender, ExposeEventArgs args) 179 | { 180 | Gdk.EventExpose evnt = args.Event; 181 | Context cr = Gdk.CairoHelper.Create (GdkWindow); 182 | 183 | /*if(composeAvailable) 184 | cr.SetSourceRGBA (0, 0, 0, 0.3); 185 | else*/ 186 | cr.SetSourceRGB (0.6, 0.6, 0.6); 187 | 188 | //cr.SetSourceRGB (0.749, 0.859, 1.0); 189 | 190 | cr.Operator = Operator.Source; 191 | cr.Paint (); 192 | 193 | ((IDisposable)cr.Target).Dispose(); 194 | ((IDisposable)cr).Dispose(); 195 | 196 | args.RetVal = false; 197 | } 198 | 199 | private void Window_OnScreenChanged (object Send, ScreenChangedArgs args) 200 | { 201 | Gdk.Colormap cm = Screen.RgbaColormap; 202 | composeAvailable = cm != null; // FIX: Do not seem to detect compose support in all cases 203 | 204 | if(!composeAvailable) cm = Screen.RgbColormap; 205 | Colormap = cm; 206 | 207 | Console.WriteLine ("Compose Support: " + composeAvailable); 208 | } 209 | 210 | private void Window_OnDelete (object send, DeleteEventArgs args) 211 | { 212 | Application.Quit (); 213 | args.RetVal = true; 214 | } 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /doc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Ribbon Lib

4 |

Widgets

5 |

Ribbon

6 |
    7 |
  • Ribbon: this is the main widget ribbon.
  • 8 |
  • RibbonGroup: groups several widgets with common functionalities.
  • 9 |
  • DropDownRibbonGroup (new 2008!): a toggle button replacing a ribbon group when space is too constrained.
    10 |
  • 11 |
  • QuickAccessToolbar (new 2008!): displays several widgets (typical shortcuts to common functionalities) next to the application button.
  • 12 |
  • VariantsCombinaisonSwitcher (new 2008!): selects a certain VariantsCombinaison based on space constraints.
    13 |
  • 14 |
15 |

Application Menu

16 |
    17 |
  • ApplicationButton (new 2008!): a button used to display the application menu. This button has a theme different than all other buttons. 
  • 18 |
  • ApplicationMenu (new 2008!): the main menu of an application, displaying application-level commands, and documents list.
  • 19 |
  • ApplicationMenuItem (new 2008!): single item to be displayed in the application menu.
  • 20 |
21 |

Common widgets

22 |
    23 |
  • Button: a simple button with optional drop down menu.
  • 24 |
  • ToggleButton: a button that remain pressed when activated by the user.
  • 25 |
  • ToolPack: packs several buttons together.
  • 26 |
  • ToolBox: displays several widgets in one or several rows depending on allocated space.
    27 |
  • 28 |
  • Gallery: displays several options to the user as thumbnails.
  • 29 |
  • Tile: a single option made available by a gallery
  • 30 |
31 |

Issues

32 |

Size negotiations

33 | The Gtk+ layout system processes in two passes: 1) size request 2) size allocation. However, in most widgets, it would be great to negotiate the size request based on size constraints (i.e. given a specific height constraint, return a width request). Currently, HeightRequest and WidthRequest properties are often used to bypass this.
34 |

Transparency

35 | The Ribbon specification requires many widgets to be transparent. However, the Gtk+ officialy requires a 'composited' desktop to support this. Nevertheless, composited desktop is still rare. In addition, the implementation of key tips requires to be able to display tiny labels on top of all widgets, and regardless of widgets' boundaries (most key tip must be displayed between two adjacent widgets). This would require many small windows to be created, or a single transparent one to be created. Currently, all widgets are used in window-less mode. Consequently, they all share the same window. However, it also disrupts the dispatchs of Gtk+ events. That's why the Ribbon library contains the SyntheticWindow class, which takes care of dispatching events to window-less widgets.
36 |

Key bindings

37 | The Ribbon library must be able to retrieve the keyboard shortcut of accelerators in order to display the key associated to each widget. The solution to this problem is still obscure.
38 |

Windows' drop shadow

39 | We should have the ability to disable drop shadow on certain window because it breaks the visual style of the Ribbon.
40 |
41 | 42 | 43 | --------------------------------------------------------------------------------