File indexing completed on 2024-05-05 05:34:56

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004 
0005     based on the Null Theme Engine for Gtk+.
0006     SPDX-FileCopyrightText: 2008 Robert Staudinger <robert.staudinger@gmail.com>
0007 
0008     SPDX-License-Identifier: LGPL-2.0-or-later
0009 */
0010 
0011 #include "oxygendemodialog.h"
0012 #include "oxygeninputdemowidget.h"
0013 #include "oxygeninfowidget.h"
0014 #include "oxygenbuttondemowidget.h"
0015 #include "oxygenframedemowidget.h"
0016 #include "oxygenlistdemowidget.h"
0017 #include "oxygensliderdemowidget.h"
0018 #include "oxygentabdemowidget.h"
0019 
0020 #include <gdk/gdkkeysyms.h>
0021 
0022 // Older (such as 2.20.1) GTK versions had different name for this
0023 #ifndef GDK_KEY_Q
0024 #define GDK_KEY_Q GDK_Q
0025 #endif
0026 
0027 #include <iostream>
0028 #include <sstream>
0029 
0030 namespace Oxygen
0031 {
0032 
0033     //_____________________________________________
0034     DemoDialog::DemoDialog( void )
0035     {
0036 
0037         // create main widget
0038         _mainWidget = gtk_window_new( GTK_WINDOW_TOPLEVEL );
0039         gtk_window_set_default_size( GTK_WINDOW( _mainWidget ), 630, 500 );
0040         gtk_window_set_title( GTK_WINDOW( _mainWidget ), "Oxygen-gtk Demo" );
0041         gtk_container_set_border_width( GTK_CONTAINER( _mainWidget ), 10 );
0042 
0043         // vertical container
0044         GtkWidget* vbox( gtk_vbox_new( false, 5 ) );
0045         gtk_container_add( GTK_CONTAINER( _mainWidget ), vbox );
0046         gtk_widget_show( vbox );
0047 
0048         GtkWidget* iconView(0L);
0049         {
0050             // first horizontal container
0051             GtkWidget* hbox( gtk_hbox_new( false, 8 ) );
0052             gtk_box_pack_start( GTK_BOX( vbox ), hbox, true, true, 0 );
0053             gtk_widget_show( hbox );
0054 
0055             // iconview model
0056             _model = gtk_list_store_new( 2, GDK_TYPE_PIXBUF, G_TYPE_STRING );
0057 
0058             // inconview
0059             GtkWidget* scrolledWindow( gtk_scrolled_window_new( 0L, 0L ) );
0060             gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( scrolledWindow ), GTK_SHADOW_IN );
0061             gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolledWindow ), GTK_POLICY_NEVER, GTK_POLICY_NEVER );
0062             gtk_box_pack_start( GTK_BOX( hbox ), scrolledWindow, false, true, 0 );
0063             gtk_widget_show( scrolledWindow );
0064 
0065             iconView = gtk_icon_view_new_with_model( GTK_TREE_MODEL( _model ) );
0066             gtk_icon_view_set_pixbuf_column( GTK_ICON_VIEW( iconView ), 0 );
0067             gtk_icon_view_set_text_column( GTK_ICON_VIEW( iconView ), 1 );
0068             gtk_icon_view_set_columns( GTK_ICON_VIEW( iconView ), 1 );
0069 
0070             gtk_icon_view_set_item_width( GTK_ICON_VIEW( iconView ), 108 );
0071             gtk_icon_view_set_spacing( GTK_ICON_VIEW( iconView ), 0 );
0072             gtk_icon_view_set_margin( GTK_ICON_VIEW( iconView ), 0 );
0073             gtk_icon_view_set_column_spacing( GTK_ICON_VIEW( iconView ), 0 );
0074             gtk_icon_view_set_row_spacing( GTK_ICON_VIEW( iconView ), 0 );
0075             gtk_icon_view_set_selection_mode( GTK_ICON_VIEW( iconView ), GTK_SELECTION_BROWSE );
0076 
0077             // get list of renderers, find text renderer and make font format bold
0078             GList* cells( gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( iconView ) ) );
0079             for( GList *cell = g_list_first( cells ); cell; cell = g_list_next( cell ) )
0080             {
0081                 if( !GTK_IS_CELL_RENDERER_TEXT( cell->data ) ) continue;
0082 
0083                 // create pango attributes list
0084                 PangoAttrList* attributes( pango_attr_list_new() );
0085                 pango_attr_list_insert( attributes, pango_attr_weight_new( PANGO_WEIGHT_BOLD ) );
0086 
0087                 GValue val = { 0, };
0088                 g_value_init(&val, PANGO_TYPE_ATTR_LIST );
0089                 g_value_set_boxed( &val, attributes );
0090                 g_object_set_property( G_OBJECT( cell->data ), "attributes", &val );
0091 
0092                 pango_attr_list_unref( attributes );
0093 
0094             }
0095 
0096             if( cells ) g_list_free( cells );
0097 
0098             // connect signals
0099             connect( G_OBJECT(iconView), "selection-changed", G_CALLBACK( selectionChanged ), this );
0100 
0101             gtk_container_add( GTK_CONTAINER( scrolledWindow ), iconView );
0102             gtk_widget_show( iconView );
0103 
0104             // notebook
0105             _notebook = gtk_notebook_new();
0106             gtk_notebook_set_show_tabs( GTK_NOTEBOOK( _notebook ), false );
0107             gtk_box_pack_start( GTK_BOX( hbox ), _notebook, true, true, 0 );
0108             gtk_widget_show( _notebook );
0109 
0110         }
0111 
0112         {
0113             // statusbar
0114             GtkWidget* statusBar( gtk_hbox_new( false, 2 ) );
0115             gtk_box_pack_start( GTK_BOX( vbox ), statusBar, false, true, 0 );
0116             gtk_widget_show( statusBar );
0117 
0118             // enable checkbox
0119             _stateButton = gtk_check_button_new_with_label( "Enabled" );
0120             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( _stateButton ), true );
0121             gtk_box_pack_start( GTK_BOX( statusBar ), _stateButton, false, false, 0 );
0122             gtk_widget_show( _stateButton );
0123 
0124             connect( G_OBJECT(_stateButton), "toggled", G_CALLBACK( toggleEnableState ), this );
0125 
0126             // widget direction checkbox
0127             GtkWidget* button( gtk_check_button_new_with_label( "Right to left layout" ) );
0128             gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( button ), false );
0129             gtk_box_pack_start( GTK_BOX( statusBar ), button, false, false, 0 );
0130             gtk_widget_show( button );
0131 
0132             connect( G_OBJECT(button), "toggled", G_CALLBACK( toggleWidgetDirection ), 0L );
0133 
0134             // button box
0135             #if GTK_CHECK_VERSION( 3, 0, 0 )
0136             GtkWidget* buttonBox( gtk_button_box_new( GTK_ORIENTATION_HORIZONTAL) );
0137             #else
0138             GtkWidget* buttonBox( gtk_hbutton_box_new() );
0139             #endif
0140 
0141             gtk_button_box_set_layout( GTK_BUTTON_BOX( buttonBox ), GTK_BUTTONBOX_END );
0142             gtk_box_pack_end( GTK_BOX( statusBar ), buttonBox, true, true, 0 );
0143             gtk_widget_show( buttonBox );
0144 
0145             // close button
0146             button = gtk_button_new_from_stock( GTK_STOCK_OK );
0147             gtk_box_pack_end( GTK_BOX( buttonBox ), button, false, true, 0 );
0148             gtk_widget_show( button );
0149 
0150             connect( G_OBJECT(button), "clicked", G_CALLBACK( gtk_main_quit ), 0L );
0151 
0152         }
0153 
0154         addPage( new InputDemoWidget() );
0155         addPage( new TabDemoWidget() );
0156         addPage( new ButtonDemoWidget() );
0157         addPage( new ListDemoWidget() );
0158         addPage( new FrameDemoWidget() );
0159         addPage( _sliderDemoWidget = new SliderDemoWidget() );
0160         addPage( new InfoWidget() );
0161 
0162         // select first raw
0163         GtkTreePath *path( gtk_tree_path_new_from_indices(0, -1 ) );
0164         gtk_icon_view_select_path( GTK_ICON_VIEW( iconView ), path );
0165         gtk_tree_path_free( path );
0166 
0167         // keypress signals
0168         connect( G_OBJECT(_mainWidget), "key-press-event", G_CALLBACK( keyPress ), 0L );
0169 
0170     }
0171 
0172     //_____________________________________________
0173     DemoDialog::~DemoDialog( void )
0174     {
0175         // delete pages
0176         for( PageMap::iterator iter = _pages.begin(); iter != _pages.end(); ++iter )
0177         { delete iter->second; }
0178     }
0179 
0180     //_____________________________________________
0181     void DemoDialog::addPage( DemoWidget* page )
0182     {
0183         // get icon
0184         GdkPixbuf* icon( 0L );
0185         if( !page->iconName().empty() )
0186         {
0187 
0188             // TODO: should get this icon size from options
0189             GtkIconTheme* theme( gtk_icon_theme_get_default() );
0190             icon = gtk_icon_theme_load_icon( theme, page->iconName().c_str(), 32, (GtkIconLookupFlags) 0, 0L );
0191 
0192         }
0193 
0194         // insert in list
0195         GtkTreeIter iter;
0196         gtk_list_store_append( _model, &iter );
0197         gtk_list_store_set( _model, &iter, 0, icon, 1, page->name().c_str(), -1 );
0198 
0199         // add to notebook
0200         int index( gtk_notebook_append_page( GTK_NOTEBOOK( _notebook ), page->mainWidget(), 0L ) );
0201         gtk_widget_show( page->mainWidget() );
0202 
0203         _pages.insert( std::make_pair( index, page ) );
0204     }
0205 
0206     //_____________________________________________
0207     void DemoDialog::selectionChanged( GtkIconView* view, gpointer data )
0208     {
0209         // get pointer to dialog
0210         DemoDialog& dialog( *static_cast<DemoDialog*>( data ) );
0211 
0212         // get selection
0213         GList* selection = gtk_icon_view_get_selected_items( view );
0214         if( !selection ) return;
0215 
0216         // get first child
0217         GtkTreePath* path( static_cast<GtkTreePath*>( g_list_first( selection )->data ) );
0218         const int page( gtk_tree_path_get_indices( path )[0] );
0219         gtk_notebook_set_current_page( GTK_NOTEBOOK( dialog._notebook ), page );
0220 
0221         // explicitly free path contained in list to avoir mem leak, before calling g_list_free
0222         for( GList *child = g_list_first( selection ); child; child = g_list_next( child ) )
0223         { gtk_tree_path_free( static_cast<GtkTreePath*>( child->data ) ); }
0224 
0225         g_list_free( selection );
0226 
0227         // store enable state
0228         const bool enabled( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON( dialog._stateButton ) ) );
0229 
0230         // get matching page
0231         DemoWidget* widget( dialog._pages[page] );
0232         widget->setEnabled( enabled );
0233         if( widget == dialog._sliderDemoWidget ) dialog._sliderDemoWidget->startPulse();
0234         else dialog._sliderDemoWidget->stopPulse();
0235 
0236         // update window title
0237         std::ostringstream what;
0238         what << widget->name() << " - Oxygen-gtk Demo";
0239         gtk_window_set_title( GTK_WINDOW( dialog._mainWidget ), what.str().c_str() );
0240     }
0241 
0242     //_____________________________________________
0243     void DemoDialog::toggleEnableState( GtkToggleButton* button, gpointer data )
0244     {
0245 
0246         // get pointer to dialog
0247         DemoDialog& dialog( *static_cast<DemoDialog*>( data ) );
0248 
0249         // store enable state
0250         const bool enabled( gtk_toggle_button_get_active( button ) );
0251 
0252         // get current page
0253         const int page( gtk_notebook_get_current_page( GTK_NOTEBOOK( dialog._notebook ) ) );
0254 
0255         // get matching page
0256         DemoWidget* widget( dialog._pages[page] );
0257 
0258         // set state
0259         widget->setEnabled( enabled );
0260 
0261         // trigger repaint
0262         gtk_widget_queue_draw( widget->mainWidget() );
0263 
0264     }
0265 
0266     //_____________________________________________
0267     void DemoDialog::toggleWidgetDirection( GtkToggleButton* button, gpointer data )
0268     { gtk_widget_set_default_direction( gtk_toggle_button_get_active( button ) ? GTK_TEXT_DIR_RTL:GTK_TEXT_DIR_LTR ); }
0269 
0270     //_____________________________________________
0271     gboolean DemoDialog::keyPress( GtkWidget* widget, GdkEventKey* event, gpointer )
0272     {
0273         guint modifiers( gtk_accelerator_get_default_mod_mask() );
0274         if( gdk_keyval_to_upper( event->keyval ) == GDK_KEY_Q && (event->state&modifiers) == GDK_CONTROL_MASK )
0275         {
0276             gtk_main_quit();
0277             return TRUE;
0278         }
0279 
0280         return FALSE;
0281     }
0282 
0283 }