Portál AbcLinuxu, 6. května 2025 08:51

Vala a buttonek s menu

3.1.2009 19:34 | Přečteno: 1203× | Jiné

Dnes objevil sem zajímavý programovací jazyk jménem Vala. Je trochu podobný C# a má vcelku jednu zajímavou vlastnost - umí generovat C kód (sice je místy trošku ošklivější) a ten pak ptohání gcc. Výsledný program je pak, narozdíl od C#, rychlý. A jelikož jsem nedávno dělal buttonek, přepsal jsem ho do tohoto jazyka.

Šlo to docela dobře, až na špatné "vapi" pro Gtk.Container.forall, takže je v souboru gtk+-2.0.vapi (obvykle v /usr/share/vala/vapi) nutno upravit argumenty z "Gtk.Callback callback" na "bool include_internals, Gtk.Callback callback" (někdo může nahlásit bug jestli není, mně se nechce). Kvůli téhle chybě mi to pořád padalo na SIGSEGV a když jsem tu metodu nepřekryl, tak mi to nechtělo kreslit buttonek a já se s tím tak dlouho trápil ...

MenuButton.vala:

using Gtk;

public class Controls.MenuButton: Gtk.Container
{
	weak Gtk.Widget  _button_widget;
	Gtk.Menu?        _menu;
	Gtk.HBox         box;
	Gtk.Arrow?       arrow;
	Gtk.Alignment?   alignment;
	Gtk.ToggleButton toggle_button;
	weak Gtk.Widget  size_widget;
	
	construct
	{	
		set_flags (WidgetFlags.NO_WINDOW);
		
		_button_widget = null;
		_menu = null;
		arrow = null;
		alignment = null;
		
		toggle_button = new ToggleButton ();
		box = new HBox (false, 0);		
		
		toggle_button.set_parent (this);
		box.set_parent (this);
		
		toggle_button.set_focus_on_click (false);
		toggle_button.set_relief (ReliefStyle.NONE);
		toggle_button.activate += on_toggle_activated;
		toggle_button.button_press_event += on_toggle_press_event;
		
		toggle_button.show ();
		box.show ();
		
		size_widget = toggle_button;
	}
	
	public MenuButton ()
	{
		show_arrow = true;
	}
	
	public void remove_button_widget ()
	{
		if (_button_widget == null) return;
		
		if (arrow != null)
		{
			box.remove (_button_widget);
		}
		else
		{
			toggle_button.remove (_button_widget);
		}
		_button_widget = null;
	}
	
	public Widget? button_widget
	{
		get { return _button_widget; }
		set {
			remove_button_widget ();
			
			if (value != null)
			{
				_button_widget = value;
				if (arrow != null)
				{
					box.pack_start (_button_widget, true, true, 0);
				}
				else
				{
					toggle_button.add (_button_widget);
				}
			}
		}
	}
	
	public bool show_arrow
	{
		get { return (arrow != null); }
		set {
			if (value)
			{
				if (arrow == null)
				{
					arrow = new Arrow (ArrowType.DOWN, ShadowType.NONE);
					alignment = new Alignment (0.0f, 0.5f, 0.0f, 0.0f);
					alignment.add (arrow);
					arrow.show ();
					alignment.show ();
					box.pack_end (alignment, false, false, 5);
			
					if (_button_widget != null)
					{
						_button_widget.ref ();
						toggle_button.remove (_button_widget);
						box.pack_start (_button_widget, true, true, 0);
						_button_widget.unref ();
					}
					size_widget = box;
				}
			}
			else if (arrow != null)
			{
				box.remove (alignment);
				arrow = null;
				alignment = null;
			
				if (_button_widget != null)
				{
					_button_widget.ref ();
					box.remove (_button_widget);
					toggle_button.add (_button_widget);
					_button_widget.unref ();
				}
				size_widget = toggle_button;
			}
		}
	}
	
	private void menu_position_func (Menu menu, out int x, out int y, out bool push_in)
	{
		Requisition menu_req = Requisition ();
		menu.size_request (out menu_req);
		
		Gdk.Screen screen;
		
		screen = get_screen ();
		
		int monitor_num = screen.get_monitor_at_window (window);
		
		Gdk.Rectangle monitor = Gdk.Rectangle ();
		screen.get_monitor_geometry (monitor_num < 0 ? 0 : monitor_num, out monitor);
		
		window.get_origin (out x, out y);
		
		y += allocation.y;
		x += allocation.x + int.max (allocation.width  - menu_req.width, 0);
		
		if (y + allocation.height + menu_req.height <= monitor.y + monitor.height)
		{
			y += allocation.height;
		}
		else if (y - menu_req.height >= monitor.y)
		{
			y -= menu_req.height;
		}
		else if (monitor.y + monitor.height - (y + allocation.height) > y)
		{
			y += allocation.height;
		}
		else
		{
			y -= menu_req.height;
		}
		push_in = false;
	}
	
	private void show_menu ()
	{
		_menu.popup (null, null, menu_position_func, 0, get_current_event_time ());
	}
	
	private bool on_toggle_press_event (ToggleButton? toggle, Gdk.EventButton? but)
	{
		if (but.button == 1)
		{
			if (_menu != null)
			{
				show_menu ();
				toggle_button.set_active (true);
			}
			return true;
		}
		else return false;
	}
	
	private void on_toggle_activated (ToggleButton? toggle)
	{
		show_menu ();
	}
	
	private void on_menu_deactivate (Menu? menu)
	{
		toggle_button.set_active (false);
	}
	
	public Menu? menu
	{
		get { return _menu; }
		
		set {
			remove_menu ();
			if (value != null)
			{
				_menu = value;
				_menu.deactivate += on_menu_deactivate;
			}
		}
	}
	
	public void remove_menu ()
	{
		if (_menu != null)
		{
			_menu.deactivate -= on_menu_deactivate;
			_menu = null;
		}
	}
	
	public override void size_allocate (Gdk.Rectangle allocation)
	{
		box.size_allocate (allocation);
		toggle_button.size_allocate (allocation);
		base.size_allocate (allocation);
	}
	
	public override void size_request (out Gtk.Requisition req)
	{
		size_widget.size_request (out req);
	}
	
	public override void add (Widget w)
	{
	
	}
	
	public override void remove (Widget w)
	{
	
	}
	
	public override void forall (bool include_internals, Gtk.Callback cb)
	{
		cb (toggle_button);
		cb (box);
	}
}
       

Hodnocení: 71 %

        špatnédobré        

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

Komentáře

Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře. , Tisk

Vložit další komentář

vlastikroot avatar 3.1.2009 20:46 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: Vala a buttonek s menu
Odpovědět | Sbalit | Link | Blokovat | Admin
Výsledný program je pak, narozdíl od C#, rychlý.
IMHO spis naopak, objektovy kod v C nemuze byt o moc rychlejsi nez v C# (oboji je runtime), zato treba C++ uz rychly je.
We will destroys the Christian's legion ... and the cross, will be inverted
3.1.2009 22:33 Zdenek
Rozbalit Rozbalit vše Re: Vala a buttonek s menu
Objektovy kod v C je runtime? A jak se neco takoveho stane?
vlastikroot avatar 3.1.2009 23:18 vlastikroot | skóre: 24 | blog: vlastikovo | Milevsko
Rozbalit Rozbalit vše Re: Vala a buttonek s menu
Kdyz beru v uvahu ze objektovy kod v C je napsany v Glib, tak je to vicemene runtime, podpora objektu je emulovana pres kupu ruznych funkci a struktur, misto optimalizovanych prekladu v C++.
We will destroys the Christian's legion ... and the cross, will be inverted
3.1.2009 23:35 Zdenek
Rozbalit Rozbalit vše Re: Vala a buttonek s menu
To ale jen verite, ze programatori g++ jsou lepsi nez programatori glib :-)
3.1.2009 23:45 Zdenek
Rozbalit Rozbalit vše Re: Vala a buttonek s menu
Mno ale mate pravdu, minimalne hash table jsou opravdu v g++ lepsi.
alblaho avatar 4.1.2009 10:44 alblaho | skóre: 17 | blog: alblog
Rozbalit Rozbalit vše Re: Vala a buttonek s menu

Právě že předpokládá, že jsou dobřít řádově stejně. g++ je nástroj na statickou analýzu objektového kódu a generování efektivního strojáku. Znásilnit k něčemu takovému překladač plain C není možné.

Jardík avatar 4.1.2009 13:33 Jardík | skóre: 40 | blog: jarda_bloguje
Rozbalit Rozbalit vše Re: Vala a buttonek s menu

Ale zase když v C++ budete používat virtuální metody a výjimky, tak to taky bude "runtime", takže ono to vyjde celkem na stejno.

Věřím v jednoho Boha.

Založit nové vláknoNahoru

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.