2014-02-16 14:55:51 -06:00
// +build !windows,!darwin,!plan9
2014-06-03 17:40:47 -05:00
// this is manual but either this or the opposite (listing all valid systems) really are the only ways to do it; proposals for a 'unix' tag were rejected (https://code.google.com/p/go/issues/detail?id=6325)
2014-02-16 14:55:51 -06:00
// 16 february 2014
2014-03-12 20:55:45 -05:00
2014-02-19 10:41:10 -06:00
package ui
2014-02-16 14:55:51 -06:00
import (
2014-04-09 11:04:04 -05:00
"fmt"
2014-02-16 14:55:51 -06:00
"unsafe"
)
2014-03-16 09:34:12 -05:00
// #include "gtk_unix.h"
2014-06-05 12:04:34 -05:00
// static inline void gtkSetComboBoxArbitrarilyResizeable(GtkWidget *w)
// {
2014-06-05 12:40:47 -05:00
// /* we can safely assume that the cell renderers of a GtkComboBoxText are a single GtkCellRendererText by default */
// /* thanks mclasen and tristan in irc.gimp.net/#gtk+ */
2014-06-05 12:04:34 -05:00
// GtkCellLayout *cbox = (GtkCellLayout *) w;
// GList *renderer;
2014-06-10 12:35:18 -05:00
//
2014-06-05 12:04:34 -05:00
// renderer = gtk_cell_layout_get_cells(cbox);
2014-06-05 12:40:47 -05:00
// g_object_set(renderer->data,
// "ellipsize-set", TRUE, /* with no ellipsizing or wrapping, the combobox won't resize */
// "ellipsize", PANGO_ELLIPSIZE_END,
// "width-chars", 0,
// NULL);
2014-06-05 12:04:34 -05:00
// g_list_free(renderer);
// }
2014-02-16 14:55:51 -06:00
import "C"
2014-06-12 11:09:24 -05:00
var gtkStyles = [ ] byte ( `
/ *
this first one is for ProgressBar so we can arbitrarily resize it
min - horizontal - bar - width is a style property ; we do it through CSS
thanks tristan in irc . gimp . net / # gtk +
* /
* {
2014-06-02 12:32:43 -05:00
- GtkProgressBar - min - horizontal - bar - width : 1 ;
2014-06-02 12:39:27 -05:00
}
2014-06-12 11:09:24 -05:00
/ *
on some themes , such as oxygen - gtk , GtkLayout draws a solid - color background , not the window background ( as GtkFixed and GtkDrawingArea do )
this CSS fixes it
thanks to drahnr and ptomato in http : //stackoverflow.com/questions/22940588/how-do-i-really-make-a-gtk-3-gtklayout-transparent-draw-theme-background
this has now been reported to the Oyxgen maintainers ( https : //bugs.kde.org/show_bug.cgi?id=333983); I'm not sure if I'll remove this or not when that's fixed (only if it breaks other styles... I *think* it breaks elementary OS? need to check again)
TODO write a program that does the comparison
* /
GtkLayout {
2014-06-02 12:39:27 -05:00
background - color : transparent ;
}
2014-06-12 11:09:24 -05:00
` )
2014-06-02 12:32:43 -05:00
2014-04-27 11:43:15 -05:00
func gtk_init ( ) error {
2014-06-10 12:35:18 -05:00
var err * C . GError = nil // redundant in Go, but let's explicitly assign it anyway
2014-04-27 11:43:15 -05:00
// gtk_init_with_args() gives us error info (thanks chpe in irc.gimp.net/#gtk+)
2014-06-02 20:25:28 -05:00
// don't worry about GTK+'s command-line arguments; they're also available as environment variables (thanks mclasen in irc.gimp.net/#gtk+)
2014-04-27 11:43:15 -05:00
result := C . gtk_init_with_args ( nil , nil , nil , nil , nil , & err )
if result == C . FALSE {
2014-06-02 12:01:36 -05:00
return fmt . Errorf ( "error actually initilaizing GTK+: %s" , fromgstr ( err . message ) )
}
2014-06-02 12:32:43 -05:00
// now apply our custom program-global styles
2014-06-10 12:35:18 -05:00
provider := C . gtk_css_provider_new ( )
2014-06-12 11:09:24 -05:00
if C . gtk_css_provider_load_from_data ( provider , ( * C . gchar ) ( unsafe . Pointer ( & gtkStyles [ 0 ] ) ) , C . gssize ( len ( gtkStyles ) ) , & err ) == C . FALSE {
2014-06-02 12:32:43 -05:00
return fmt . Errorf ( "error applying package ui's custom program-global styles to GTK+: %v" , fromgstr ( err . message ) )
2014-04-27 11:43:15 -05:00
}
2014-06-02 12:32:43 -05:00
// GDK (at least as far back as GTK+ 3.4, but officially documented as of 3.10) merges all screens into one big one, so we don't need to worry about multimonitor
// thanks to baedert and mclasen in irc.gimp.net/#gtk+
C . gtk_style_context_add_provider_for_screen ( C . gdk_screen_get_default ( ) ,
( * C . GtkStyleProvider ) ( unsafe . Pointer ( provider ) ) ,
C . GTK_STYLE_PROVIDER_PRIORITY_USER )
2014-04-27 11:43:15 -05:00
return nil
2014-02-16 16:09:58 -06:00
}
2014-03-05 12:25:19 -06:00
func gtk_main_quit ( ) {
C . gtk_main_quit ( )
}
2014-04-01 15:30:38 -05:00
func gtk_window_new ( ) * C . GtkWidget {
return C . gtk_window_new ( C . GTK_WINDOW_TOPLEVEL )
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_widget_show ( widget * C . GtkWidget ) {
C . gtk_widget_show_all ( widget )
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_widget_hide ( widget * C . GtkWidget ) {
C . gtk_widget_hide ( widget )
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_window_set_title ( window * C . GtkWidget , title string ) {
2014-02-16 14:55:51 -06:00
ctitle := C . CString ( title )
defer C . free ( unsafe . Pointer ( ctitle ) )
2014-04-26 21:55:43 -05:00
C . gtk_window_set_title ( togtkwindow ( window ) , togstr ( ctitle ) )
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_window_get_title ( window * C . GtkWidget ) string {
2014-04-26 21:55:43 -05:00
return fromgstr ( C . gtk_window_get_title ( togtkwindow ( window ) ) )
2014-02-16 17:57:50 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_window_resize ( window * C . GtkWidget , width int , height int ) {
2014-02-17 14:45:26 -06:00
C . gtk_window_resize ( togtkwindow ( window ) , C . gint ( width ) , C . gint ( height ) )
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_window_get_size ( window * C . GtkWidget ) ( int , int ) {
2014-02-16 17:04:57 -06:00
var width , height C . gint
2014-02-17 14:45:26 -06:00
C . gtk_window_get_size ( togtkwindow ( window ) , & width , & height )
2014-02-16 17:04:57 -06:00
return int ( width ) , int ( height )
}
2014-03-15 13:27:18 -05:00
// this should allow us to resize the window arbitrarily
// thanks to Company in irc.gimp.net/#gtk+
2014-04-01 15:30:38 -05:00
func gtkNewWindowLayout ( ) * C . GtkWidget {
2014-03-15 13:27:18 -05:00
layout := C . gtk_layout_new ( nil , nil )
scrollarea := C . gtk_scrolled_window_new ( ( * C . GtkAdjustment ) ( nil ) , ( * C . GtkAdjustment ) ( nil ) )
C . gtk_container_add ( ( * C . GtkContainer ) ( unsafe . Pointer ( scrollarea ) ) , layout )
// never show scrollbars; we're just doing this to allow arbitrary resizes
C . gtk_scrolled_window_set_policy ( ( * C . GtkScrolledWindow ) ( unsafe . Pointer ( scrollarea ) ) ,
C . GTK_POLICY_NEVER , C . GTK_POLICY_NEVER )
2014-04-01 15:30:38 -05:00
return scrollarea
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_container_add ( container * C . GtkWidget , widget * C . GtkWidget ) {
C . gtk_container_add ( togtkcontainer ( container ) , widget )
2014-02-16 14:55:51 -06:00
}
2014-04-01 15:30:38 -05:00
func gtkAddWidgetToLayout ( container * C . GtkWidget , widget * C . GtkWidget ) {
2014-03-15 13:27:18 -05:00
layout := C . gtk_bin_get_child ( ( * C . GtkBin ) ( unsafe . Pointer ( container ) ) )
2014-04-01 15:30:38 -05:00
C . gtk_container_add ( ( * C . GtkContainer ) ( unsafe . Pointer ( layout ) ) , widget )
2014-03-15 13:27:18 -05:00
}
2014-04-01 15:30:38 -05:00
func gtkMoveWidgetInLayout ( container * C . GtkWidget , widget * C . GtkWidget , x int , y int ) {
2014-03-15 13:27:18 -05:00
layout := C . gtk_bin_get_child ( ( * C . GtkBin ) ( unsafe . Pointer ( container ) ) )
2014-04-01 15:30:38 -05:00
C . gtk_layout_move ( ( * C . GtkLayout ) ( unsafe . Pointer ( layout ) ) , widget ,
2014-02-16 14:55:51 -06:00
C . gint ( x ) , C . gint ( y ) )
}
2014-04-01 15:30:38 -05:00
func gtk_widget_set_size_request ( widget * C . GtkWidget , width int , height int ) {
C . gtk_widget_set_size_request ( widget , C . gint ( width ) , C . gint ( height ) )
2014-02-16 14:55:51 -06:00
}
2014-02-16 16:30:58 -06:00
2014-04-01 15:30:38 -05:00
func gtk_button_new ( ) * C . GtkWidget {
return C . gtk_button_new ( )
2014-02-16 16:30:58 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_button_set_label ( button * C . GtkWidget , label string ) {
2014-02-16 16:30:58 -06:00
clabel := C . CString ( label )
defer C . free ( unsafe . Pointer ( clabel ) )
2014-04-26 21:55:43 -05:00
C . gtk_button_set_label ( togtkbutton ( button ) , togstr ( clabel ) )
2014-02-16 16:30:58 -06:00
}
2014-02-16 17:41:29 -06:00
2014-04-01 15:30:38 -05:00
func gtk_button_get_label ( button * C . GtkWidget ) string {
2014-04-26 21:55:43 -05:00
return fromgstr ( C . gtk_button_get_label ( togtkbutton ( button ) ) )
2014-02-16 17:57:50 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_check_button_new ( ) * C . GtkWidget {
return C . gtk_check_button_new ( )
2014-02-16 17:41:29 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_toggle_button_get_active ( widget * C . GtkWidget ) bool {
2014-02-17 14:45:26 -06:00
return fromgbool ( C . gtk_toggle_button_get_active ( togtktogglebutton ( widget ) ) )
2014-02-16 17:41:29 -06:00
}
2014-02-16 18:50:52 -06:00
2014-04-01 15:30:38 -05:00
func gtk_combo_box_text_new ( ) * C . GtkWidget {
2014-06-05 12:04:34 -05:00
w := C . gtk_combo_box_text_new ( )
C . gtkSetComboBoxArbitrarilyResizeable ( w )
return w
2014-02-16 18:50:52 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_combo_box_text_new_with_entry ( ) * C . GtkWidget {
2014-06-05 12:04:34 -05:00
w := C . gtk_combo_box_text_new_with_entry ( )
// we need to set the entry's width-chars to achieve the arbitrary sizing we want
// thanks to tristan in irc.gimp.net/#gtk+
2014-06-05 12:40:47 -05:00
// in my tests, this is sufficient to get the effect we want; setting the cell renderer isn't necessary like it is with an entry-less combobox
2014-06-05 12:04:34 -05:00
entry := togtkentry ( C . gtk_bin_get_child ( ( * C . GtkBin ) ( unsafe . Pointer ( w ) ) ) )
C . gtk_entry_set_width_chars ( entry , 0 )
return w
2014-02-16 18:50:52 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_combo_box_text_get_active_text ( widget * C . GtkWidget ) string {
2014-04-26 21:55:43 -05:00
return fromgstr ( C . gtk_combo_box_text_get_active_text ( togtkcombobox ( widget ) ) )
2014-02-16 18:50:52 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_combo_box_text_append_text ( widget * C . GtkWidget , text string ) {
2014-02-16 18:50:52 -06:00
ctext := C . CString ( text )
defer C . free ( unsafe . Pointer ( ctext ) )
2014-04-26 21:55:43 -05:00
C . gtk_combo_box_text_append_text ( togtkcombobox ( widget ) , togstr ( ctext ) )
2014-02-16 18:50:52 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_combo_box_text_insert_text ( widget * C . GtkWidget , index int , text string ) {
2014-02-16 18:50:52 -06:00
ctext := C . CString ( text )
defer C . free ( unsafe . Pointer ( ctext ) )
2014-04-26 21:55:43 -05:00
C . gtk_combo_box_text_insert_text ( togtkcombobox ( widget ) , C . gint ( index ) , togstr ( ctext ) )
2014-02-16 18:50:52 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_combo_box_get_active ( widget * C . GtkWidget ) int {
2014-02-17 14:45:26 -06:00
cb := ( * C . GtkComboBox ) ( unsafe . Pointer ( widget ) )
return int ( C . gtk_combo_box_get_active ( cb ) )
2014-02-16 18:50:52 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_combo_box_text_remove ( widget * C . GtkWidget , index int ) {
2014-02-17 14:45:26 -06:00
C . gtk_combo_box_text_remove ( togtkcombobox ( widget ) , C . gint ( index ) )
2014-02-16 18:50:52 -06:00
}
2014-02-16 20:40:59 -06:00
2014-04-01 15:30:38 -05:00
func gtkComboBoxLen ( widget * C . GtkWidget ) int {
2014-03-08 15:42:57 -06:00
cb := ( * C . GtkComboBox ) ( unsafe . Pointer ( widget ) )
model := C . gtk_combo_box_get_model ( cb )
// this is the same as with a Listbox so
return gtkTreeModelListLen ( model )
}
2014-04-01 15:30:38 -05:00
func gtk_entry_new ( ) * C . GtkWidget {
2014-05-24 20:28:28 -05:00
e := C . gtk_entry_new ( )
// allows the GtkEntry to be resized with the window smaller than what it thinks the size should be
// thanks to Company in irc.gimp.net/#gtk+
C . gtk_entry_set_width_chars ( togtkentry ( e ) , 0 )
return e
2014-02-16 20:40:59 -06:00
}
2014-04-01 15:30:38 -05:00
func gtkPasswordEntryNew ( ) * C . GtkWidget {
2014-02-25 14:06:51 -06:00
e := gtk_entry_new ( )
C . gtk_entry_set_visibility ( togtkentry ( e ) , C . FALSE )
return e
}
2014-04-01 15:30:38 -05:00
func gtk_entry_set_text ( widget * C . GtkWidget , text string ) {
2014-02-16 20:40:59 -06:00
ctext := C . CString ( text )
defer C . free ( unsafe . Pointer ( ctext ) )
2014-04-26 21:55:43 -05:00
C . gtk_entry_set_text ( togtkentry ( widget ) , togstr ( ctext ) )
2014-02-16 20:40:59 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_entry_get_text ( widget * C . GtkWidget ) string {
2014-04-26 21:55:43 -05:00
return fromgstr ( C . gtk_entry_get_text ( togtkentry ( widget ) ) )
2014-02-16 20:40:59 -06:00
}
2014-02-16 21:03:14 -06:00
var _emptystring = [ 1 ] C . gchar { 0 }
var emptystring = & _emptystring [ 0 ]
2014-04-01 15:30:38 -05:00
func gtk_label_new ( ) * C . GtkWidget {
2014-04-13 17:05:07 -05:00
label := C . gtk_label_new ( emptystring )
2014-06-10 12:35:18 -05:00
C . gtk_label_set_line_wrap ( togtklabel ( label ) , C . FALSE ) // turn off line wrap
2014-04-27 19:47:37 -05:00
// don't call gtk_label_set_line_wrap_mode(); there's no "wrap none" value there anyway
2014-06-10 12:35:18 -05:00
C . gtk_label_set_ellipsize ( togtklabel ( label ) , C . PANGO_ELLIPSIZE_NONE ) // turn off ellipsizing; this + line wrapping above will guarantee cutoff as documented
2014-06-02 14:22:31 -05:00
// there's a function gtk_label_set_justify() that indicates GTK_JUSTIFY_LEFT is the default
// but this actually is NOT the control justification, just the multi-line justification
// so we need to do THIS instead
2014-06-25 10:39:06 -05:00
// this will valign to the center, which is what the HIG says (https://developer.gnome.org/hig-book/3.4/design-text-labels.html.en) for all controls that label to the side; thankfully this means we don't need to do any extra positioning magic
2014-06-02 14:22:31 -05:00
// this will also valign to the top
// thanks to mclasen in irc.gimp.net/#gtk+
2014-06-25 10:39:06 -05:00
C . gtk_misc_set_alignment ( ( * C . GtkMisc ) ( unsafe . Pointer ( label ) ) , 0 , 0.5 )
return label
}
func gtk_label_new_standalone ( ) * C . GtkWidget {
label := gtk_label_new ( )
// this will valign to the top
2014-06-02 14:22:31 -05:00
C . gtk_misc_set_alignment ( ( * C . GtkMisc ) ( unsafe . Pointer ( label ) ) , 0 , 0 )
2014-04-13 17:05:07 -05:00
return label
2014-02-16 21:03:14 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_label_set_text ( widget * C . GtkWidget , text string ) {
2014-02-16 21:03:14 -06:00
ctext := C . CString ( text )
defer C . free ( unsafe . Pointer ( ctext ) )
2014-04-26 21:55:43 -05:00
C . gtk_label_set_text ( togtklabel ( widget ) , togstr ( ctext ) )
2014-02-16 21:03:14 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_label_get_text ( widget * C . GtkWidget ) string {
2014-04-26 21:55:43 -05:00
return fromgstr ( C . gtk_label_get_text ( togtklabel ( widget ) ) )
2014-02-16 21:03:14 -06:00
}
2014-02-23 19:04:33 -06:00
2014-04-01 15:30:38 -05:00
func gtk_widget_get_preferred_size ( widget * C . GtkWidget ) ( minWidth int , minHeight int , natWidth int , natHeight int ) {
2014-02-23 19:04:33 -06:00
var minimum , natural C . GtkRequisition
2014-04-01 15:30:38 -05:00
C . gtk_widget_get_preferred_size ( widget , & minimum , & natural )
2014-02-23 19:04:33 -06:00
return int ( minimum . width ) , int ( minimum . height ) ,
int ( natural . width ) , int ( natural . height )
}
2014-02-24 23:48:23 -06:00
2014-04-01 15:30:38 -05:00
func gtk_progress_bar_new ( ) * C . GtkWidget {
2014-06-02 12:01:36 -05:00
return C . gtk_progress_bar_new ( )
2014-02-24 23:48:23 -06:00
}
2014-04-01 15:30:38 -05:00
func gtk_progress_bar_set_fraction ( w * C . GtkWidget , percent int ) {
2014-02-24 23:48:23 -06:00
p := C . gdouble ( percent ) / 100
C . gtk_progress_bar_set_fraction ( togtkprogressbar ( w ) , p )
}
2014-03-12 16:31:13 -05:00
2014-04-01 15:30:38 -05:00
func gtk_progress_bar_pulse ( w * C . GtkWidget ) {
2014-03-12 16:31:13 -05:00
C . gtk_progress_bar_pulse ( togtkprogressbar ( w ) )
}