From 6db08d5a0c350793b556248c85b8b72af6cc5632 Mon Sep 17 00:00:00 2001 From: michael Date: Tue, 10 Jul 2001 21:54:31 +0000 Subject: [PATCH] + Initial check-in --- docs/gtk1ex/ex1.pp | 23 ++++ docs/gtk1ex/ex2.pp | 28 +++++ docs/gtk1ex/ex3.pp | 55 +++++++++ docs/gtk1ex/ex4.pp | 46 +++++++ docs/gtk1ex/ex5.pp | 31 +++++ docs/gtk1ex/ex6.pp | 71 +++++++++++ docs/gtk1ex/ex7.pp | 54 ++++++++ docs/gtk1ex/ex8.pp | 40 ++++++ docs/gtk1ex/ex9.pp | 62 ++++++++++ docs/gtk4ex/delete.xpm | 25 ++++ docs/gtk4ex/dirlist.inc | 115 +++++++++++++++++ docs/gtk4ex/factions.inc | 33 +++++ docs/gtk4ex/filelist.inc | 213 ++++++++++++++++++++++++++++++++ docs/gtk4ex/filemask.png | Bin 0 -> 2746 bytes docs/gtk4ex/fileprops.png | Bin 0 -> 5170 bytes docs/gtk4ex/frmabout.pp | 66 ++++++++++ docs/gtk4ex/frmmain.pp | 244 +++++++++++++++++++++++++++++++++++++ docs/gtk4ex/frmmask.pp | 88 +++++++++++++ docs/gtk4ex/frmprops.pp | 130 ++++++++++++++++++++ docs/gtk4ex/futils.pp | 92 ++++++++++++++ docs/gtk4ex/fx.pp | 14 +++ docs/gtk4ex/fxbitmaps.pp | 78 ++++++++++++ docs/gtk4ex/mainwin.png | Bin 0 -> 20275 bytes docs/gtk4ex/menus.pp | 209 +++++++++++++++++++++++++++++++ docs/gtk4ex/properties.xpm | 27 ++++ 25 files changed, 1744 insertions(+) create mode 100644 docs/gtk1ex/ex1.pp create mode 100644 docs/gtk1ex/ex2.pp create mode 100644 docs/gtk1ex/ex3.pp create mode 100644 docs/gtk1ex/ex4.pp create mode 100644 docs/gtk1ex/ex5.pp create mode 100644 docs/gtk1ex/ex6.pp create mode 100644 docs/gtk1ex/ex7.pp create mode 100644 docs/gtk1ex/ex8.pp create mode 100644 docs/gtk1ex/ex9.pp create mode 100644 docs/gtk4ex/delete.xpm create mode 100644 docs/gtk4ex/dirlist.inc create mode 100644 docs/gtk4ex/factions.inc create mode 100644 docs/gtk4ex/filelist.inc create mode 100644 docs/gtk4ex/filemask.png create mode 100644 docs/gtk4ex/fileprops.png create mode 100644 docs/gtk4ex/frmabout.pp create mode 100644 docs/gtk4ex/frmmain.pp create mode 100644 docs/gtk4ex/frmmask.pp create mode 100644 docs/gtk4ex/frmprops.pp create mode 100644 docs/gtk4ex/futils.pp create mode 100644 docs/gtk4ex/fx.pp create mode 100644 docs/gtk4ex/fxbitmaps.pp create mode 100644 docs/gtk4ex/mainwin.png create mode 100644 docs/gtk4ex/menus.pp create mode 100644 docs/gtk4ex/properties.xpm diff --git a/docs/gtk1ex/ex1.pp b/docs/gtk1ex/ex1.pp new file mode 100644 index 0000000000..f87cfc09e9 --- /dev/null +++ b/docs/gtk1ex/ex1.pp @@ -0,0 +1,23 @@ +program ex1; + +{$mode objfpc} + +uses + glib,gtk; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +var + window : pGtkWidget; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (pGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + gtk_widget_show (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex2.pp b/docs/gtk1ex/ex2.pp new file mode 100644 index 0000000000..e370cfae16 --- /dev/null +++ b/docs/gtk1ex/ex2.pp @@ -0,0 +1,28 @@ +program ex2; + +{$mode objfpc} + +uses + glib,gtk; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +var + window : PGtkWidget; + button : PGtkWidget; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + button := gtk_button_new_with_label('Click me'); + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),button); + gtk_signal_connect (PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + gtk_widget_show (button); + gtk_widget_show (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex3.pp b/docs/gtk1ex/ex3.pp new file mode 100644 index 0000000000..db2b108310 --- /dev/null +++ b/docs/gtk1ex/ex3.pp @@ -0,0 +1,55 @@ +program ex3; + +{$mode objfpc} + +uses + glib,gtk; + +function newbutton(ALabel : PChar) : PGtkWidget; + +begin + Result:=gtk_button_new_with_label(ALabel); + gtk_widget_show(result); +end; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +var + window, + totalbox, + hbox,vbox : PgtkWidget; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + // Box to divide window in 2 halves: + totalbox := gtk_vbox_new(true,10); + gtk_widget_show(totalbox); + // A box for each half of the screen: + hbox := gtk_hbox_new(false,5); + gtk_widget_show(hbox); + vbox := gtk_vbox_new(true,5); + gtk_widget_show(vbox); + // Put boxes in their halves + gtk_box_pack_start(GTK_BOX(totalbox),hbox,true,true,0); + gtk_box_pack_start(GTK_BOX(totalbox),vbox,true,true,0); + // Now fill boxes with buttons. + // Horizontal box + gtk_box_pack_start(GTK_BOX(hbox),newbutton('Button 1'),false,false,0); + gtk_box_pack_start(GTK_BOX(hbox),newbutton('Button 2'),false,false,0); + gtk_box_pack_start(GTK_BOX(hbox),newbutton('Button 3'),false,false,0); + // Vertical box + gtk_box_pack_start(GTK_BOX(vbox),newbutton('Button A'),true,true,0); + gtk_box_pack_start(GTK_BOX(vbox),newbutton('Button B'),true,true,0); + gtk_box_pack_start(GTK_BOX(vbox),newbutton('Button C'),true,true,0); + // Put totalbox in window + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),totalbox); + gtk_signal_connect (PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + gtk_widget_show (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex4.pp b/docs/gtk1ex/ex4.pp new file mode 100644 index 0000000000..5f2f78fe6e --- /dev/null +++ b/docs/gtk1ex/ex4.pp @@ -0,0 +1,46 @@ +program ex4; + +{$mode objfpc} + +uses + glib,gtk; + +function newbutton(ALabel : PChar) : PGtkWidget; + +begin + Result:=gtk_button_new_with_label(ALabel); + gtk_widget_show(result); +end; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +var + window, + maintable: PgtkWidget; + +procedure AddToTable(Widget : PGtkWidget; + Left,Right, Top,Bottom : guint); +begin + gtk_table_attach_defaults (GTK_TABLE(MainTable),Widget, + Left,right,top,bottom); +end; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + Maintable := gtk_table_new(6,6,True); + gtk_widget_show(MainTable); + AddToTable(newbutton('1,1 At 1,1'),1,2,1,2); + AddToTable(newbutton('2,2 At 3,1'),3,5,1,3); + AddToTable(newbutton('4,1 At 4,1'),1,5,4,5); + // Put all in window + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),maintable); + gtk_signal_connect (PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + gtk_widget_show (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex5.pp b/docs/gtk1ex/ex5.pp new file mode 100644 index 0000000000..1b9245b99e --- /dev/null +++ b/docs/gtk1ex/ex5.pp @@ -0,0 +1,31 @@ +program ex5; + +{$mode objfpc} + +uses + glib,gtk; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +var + window : PGtkWidget; + button : PGtkWidget; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + button := gtk_button_new_with_label('Click me'); + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),button); + gtk_signal_connect (PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + gtk_signal_connect_object(PGTKOBJECT(button),'clicked', + GTK_SIGNAL_FUNC(@gtk_widget_destroy), + PGTKOBJECT(window)); + gtk_widget_show (button); + gtk_widget_show (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex6.pp b/docs/gtk1ex/ex6.pp new file mode 100644 index 0000000000..b96b8d6f4d --- /dev/null +++ b/docs/gtk1ex/ex6.pp @@ -0,0 +1,71 @@ +program ex6; + +{$mode objfpc} + +uses + glib,gtk; + +Type + TButtonSignalState = Record + Obj : PgtkObject; + SignalID : longint; + Disable : Boolean; + end; + PButtonSignalState = ^TButtonSignalState; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + + +procedure disablesignal(widget : pGtkWidget ; data: pgpointer ); cdecl; + + +begin + With PButtonSignalState(Data)^ do + begin + If Disable then + gtk_signal_handler_block(Obj,SignalID) + else + gtk_signal_handler_unblock(Obj,SignalID); + disable:=Not disable; + end; +end; + +var + window : PGtkWidget; + quitbutton : PGtkWidget; + disablebutton : PGTKWidget; + windowbox : PGTKWidget; + quitsignal : guint; + QuitState : TButtonSignalState; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + quitbutton := gtk_button_new_with_label('Quit program'); + disablebutton := gtk_button_new_with_label('Disable button'); + windowbox:=gtk_vbox_new(TRUE,10); + gtk_box_pack_start(GTK_BOX(windowbox),disablebutton,True,false,0); + gtk_box_pack_start(GTK_BOX(windowbox),quitbutton,True,false,0); + gtk_container_set_border_width(GTK_CONTAINER(Window),10); + gtk_container_add(GTK_Container(window),windowbox); + gtk_signal_connect (PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + With QuitState do + begin + Obj:=PGTKObject(QuitButton); + SignalID:=gtk_signal_connect_object(Obj,'clicked', + GTK_SIGNAL_FUNC(@gtk_widget_destroy), + PGTKOBJECT(window)); + Disable:=True; + end; + gtk_signal_connect(PGTKOBJECT(disablebutton),'clicked', + GTK_SIGNAL_FUNC(@disablesignal),@QuitState); + gtk_widget_show (quitbutton); + gtk_widget_show (disablebutton); + gtk_widget_show (windowbox); + gtk_widget_show (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex7.pp b/docs/gtk1ex/ex7.pp new file mode 100644 index 0000000000..85b86dbca8 --- /dev/null +++ b/docs/gtk1ex/ex7.pp @@ -0,0 +1,54 @@ +program ex2; + +uses + gdk,glib,gtk,strings; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +Const + Inside : PChar ='Mouse is over label'; + OutSide : PChar ='Mouse is not over label'; + +var + OverLabel : Boolean; + window, box1, box2, stackbox, label1, Label2 : PGtkWidget; + +Procedure ChangeLabel(P : PGtkWidget; + Event : PGdkEventCrossing; + Var Data : Boolean);cdecl; + +begin + If Not Data then + gtk_label_set_text(PGTKLABEL(Label2),Inside) + else + gtk_label_set_text(PGTKLABEL(Label2),Outside); + Data := Not Data; +end; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + stackbox:=gtk_vbox_new(TRUE,10); + box1 := gtk_event_box_new(); + label1 := gtk_label_new(strnew('Move mouse over label')); + gtk_container_add(GTK_CONTAINER(box1),label1); + box2 := gtk_event_box_new(); + label2 := gtk_label_new(strNew(OutSide)); + gtk_container_add(GTK_CONTAINER(box2),label2); + gtk_box_pack_start(GTK_BOX(stackbox),box1,TRUE,TRUE,0); + gtk_box_pack_start(GTK_BOX(stackbox),box2,TRUE,TRUE,0); + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),stackbox); + gtk_signal_connect(PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + overlabel:=False; + gtk_signal_connect(PGTKOBJECT(box1),'enter_notify_event', + GTK_SIGNAL_FUNC (@ChangeLabel), @Overlabel); + gtk_signal_connect(PGTKOBJECT(box1),'leave_notify_event', + GTK_SIGNAL_FUNC (@ChangeLabel), @Overlabel); + gtk_widget_show_all (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex8.pp b/docs/gtk1ex/ex8.pp new file mode 100644 index 0000000000..d99b454e48 --- /dev/null +++ b/docs/gtk1ex/ex8.pp @@ -0,0 +1,40 @@ +program ex8; + +uses + glib,gtk; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +var + window, stackbox, label1, Label2 : PGtkWidget; + labelstyle : pgtkstyle; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + stackbox:=gtk_vbox_new(TRUE,10); + label1 := gtk_label_new('Red label text'); + labelstyle := gtk_style_copy(gtk_widget_get_style(label1)); + With LabelStyle^.fg[GTK_STATE_NORMAL] do + begin + pixel:=0; + red:=$ffff; + blue:=0; + green:=0; + end; + gtk_widget_set_style(label1,labelstyle); + // Uncomment this to see the effect of setting the default style. + // gtk_widget_set_default_style(labelstyle); + label2 := gtk_label_new('Black label text'); + gtk_box_pack_start(GTK_BOX(stackbox),label1,TRUE,TRUE,0); + gtk_box_pack_start(GTK_BOX(stackbox),label2,TRUE,TRUE,0); + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),stackbox); + gtk_signal_connect(PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + gtk_widget_show_all (window); + gtk_main (); +end. diff --git a/docs/gtk1ex/ex9.pp b/docs/gtk1ex/ex9.pp new file mode 100644 index 0000000000..763512a1c3 --- /dev/null +++ b/docs/gtk1ex/ex9.pp @@ -0,0 +1,62 @@ +program ex9; + +uses + gdk,glib,gtk,strings; + +procedure destroy(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + gtk_main_quit(); +end; + +Const + Inside : PChar ='Mouse is over label'; + OutSide : PChar ='Mouse is not over label'; + +var + window, button1,Button2, Alabel,stackbox : PGtkWidget; + buttonstyle : pgtkstyle; + OverButton : boolean; + +Procedure ChangeLabel(P : PGtkWidget; + Event : PGdkEventCrossing; + Var Data : Boolean);cdecl; + +begin + If Not Data then + gtk_label_set_text(PGTKLABEL(ALabel),Inside) + else + gtk_label_set_text(PGTKLABEL(ALabel),Outside); + Data := Not Data; +end; + +begin + gtk_init (@argc, @argv); + window := gtk_window_new (GTK_WINDOW_TOPLEVEL); + stackbox:=gtk_vbox_new(TRUE,10); + button1 := gtk_button_new_with_label(strnew('Move mouse over button')); + buttonstyle := gtk_style_copy(gtk_widget_get_style(Button1)); + With ButtonStyle^.bg[GTK_STATE_PRELIGHT] do + begin + pixel:=0; + red:=$ffff; + blue:=0; + green:=0; + end; + gtk_widget_set_style(button1,buttonstyle); + button2 := gtk_button_new; + ALabel:=gtk_label_new(Outside); + gtk_container_add(GTK_CONTAINER(button2),ALAbel); + gtk_box_pack_start(GTK_BOX(stackbox),button1,TRUE,TRUE,0); + gtk_box_pack_start(GTK_BOX(stackbox),button2,TRUE,TRUE,0); + gtk_container_set_border_width(GTK_CONTAINER(Window),5); + gtk_container_add(GTK_Container(window),stackbox); + gtk_signal_connect(PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), NULL); + overbutton:=False; + gtk_signal_connect(PGTKOBJECT(button1),'enter_notify_event', + GTK_SIGNAL_FUNC (@ChangeLabel), @OverButton); + gtk_signal_connect(PGTKOBJECT(button1),'leave_notify_event', + GTK_SIGNAL_FUNC (@ChangeLabel), @OverButton); + gtk_widget_show_all (window); + gtk_main (); +end. diff --git a/docs/gtk4ex/delete.xpm b/docs/gtk4ex/delete.xpm new file mode 100644 index 0000000000..4a8efda4cc --- /dev/null +++ b/docs/gtk4ex/delete.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *delete[] = { +/* width height num_colors chars_per_pixel */ +" 16 16 2 1", +/* colors */ +". c #000000", +"# c #c0c0c0", +/* pixels */ +"################", +"################", +"##...#########.#", +"##....######..##", +"###....####..###", +"#####...##..####", +"######.....#####", +"#######...######", +"######.....#####", +"#####...##..####", +"####...####..###", +"###...######.###", +"##....#######.##", +"##...###########", +"###.##########.#", +"################" +}; diff --git a/docs/gtk4ex/dirlist.inc b/docs/gtk4ex/dirlist.inc new file mode 100644 index 0000000000..8a8cea8560 --- /dev/null +++ b/docs/gtk4ex/dirlist.inc @@ -0,0 +1,115 @@ + +Procedure Scandirs(Path: String; Tree : PgtkTree; + Node: PGtkTreeItem ; SubSub : Boolean; + Window : PMainWindow); forward; + + +Function GetPathName(Item : PGtkTreeItem) : String; + +Var P : PChar; + PTree : PGtkTree; +begin + gtk_label_get(PgtkLabel(PGtkBin(Item)^.Child),@P); + Result:=StrPas(P); + If (PGtkWidget(item)^.Parent<>Nil) then + begin + PTree:=PGtkTree(PgtkWidget(Item)^.Parent); + If (Ptree^.Level<>0) Then + Result:=AddTrailingSeparator(GetPathName(PgtkTreeItem(PTree^.Tree_Owner)))+Result + end; +end; + +Procedure DirSelect(Item : PGtkTreeItem; Window : PMainWindow);cdecl; + +begin + ShowDir(Window,GetPathName(Item)); +end; + +Procedure DirExpand(Item : PGtkTreeItem; Window : PMainWindow);cdecl; + +Var + Dir : String; + SubTree : PGtkTree; + SubNodes : PGList; + Node : PGtkTreeItem; + +begin + SubTree:=PgtkTree(Item^.SubTree); + SubNodes:=gtk_container_children(PGtkContainer(SubTree)); + While SubNodes<>Nil do + begin + Node:=PgtkTreeItem(SubNodes^.Data); + If (Node^.SubTree<>Nil) then + gtk_tree_item_remove_subtree(Node); + Scandirs(GetPathName(Node),Nil,Node,False,Window); + SubNodes:=g_list_remove_link(SubNodes,SubNodes); + end; +end; + +Procedure Scandirs(Path: String; Tree : PgtkTree; + Node: PGtkTreeItem ; SubSub : Boolean; + Window : PMainWindow); + +Var + NewTree : PGtkTree; + NewNode : PGtkTreeItem; + Info : TSearchRec; + S,FP : AnsiString; + +begin + NewTree:=Nil; + FP:=AddTrailingSeparator(Path); + If FindFirst(FP+'*.*',faAnyfile,Info)=0 then + Try + repeat + If ((Info.Attr and faDirectory)=faDirectory) then + begin + S:=Info.Name; + If (S<>'.') and (S<>'..') then + begin + If (Node<>Nil) then + begin + If (NewTree=Nil) and (node<>Nil) then + begin + NewTree:=PGtkTree(gtk_tree_new); + gtk_tree_item_set_subtree(Node,PGtkWidget(NewTree)); + end + end + else + NewTree:=Tree; + NewNode:=PGtkTreeItem(gtk_tree_item_new_with_label(Pchar(S))); + gtk_tree_append(NewTree,PgtkWidget(NewNode)); + gtk_signal_connect(PGtkObject(NewNode),'select', + TGtkSignalFunc(@DirSelect),Window); + gtk_signal_connect(PGtkObject(NewNode),'expand', + TGtkSignalFunc(@DirExpand),Window); + If SubSub then + ScanDirs(FP+S,Tree,NewNode,False,Window); + gtk_widget_show(PGtkWidget(NewNode)); + end; + end; + until FindNext(Info)<>0; + Finally + FindClose(Info); + end; + gtk_widget_show(PGtkWidget(Node)); +end; + +Function NewDirtree (MainWindow : PMainWindow) : PGtkTree; + +begin + Result:=PGtkTree(gtk_tree_new()); + With MainWindow^ do + begin + TreeScrollWindow:=PGtkScrolledWindow(gtk_scrolled_window_new(Nil,Nil)); + gtk_widget_show(PGtkWidget(TreeScrollWindow)); + gtk_scrolled_window_set_policy(TreeScrollWindow, + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_add_with_viewport(TreeScrollWindow,PGtkWidget(Result)); + RootNode:=PGtkTreeItem(gtk_tree_Item_new_with_label(Pchar(PathSeparator))); + gtk_tree_append(Result,PgtkWidget(RootNode)); + scandirs(PathSeparator,Result, RootNode,True,MainWindow); + gtk_tree_item_expand(rootnode); + end; +end; diff --git a/docs/gtk4ex/factions.inc b/docs/gtk4ex/factions.inc new file mode 100644 index 0000000000..cfe2e8ab4b --- /dev/null +++ b/docs/gtk4ex/factions.inc @@ -0,0 +1,33 @@ +Procedure DoProperties(widget : pGtkWidget ; Window : PMainWindow); cdecl; + +Var i : longint; + S : string; + Dlg : PFilePropertiesDialog; + +begin + With Window^ do + S:=AddTrailingSeparator(FDir)+GetFileFirstSelection(FileList); + Dlg:=NewFilePropertiesDialog(S); + ShowFilePropertiesDialog(Dlg); +end; + +Procedure DeleteFile(Widget : PGtkWidget; Window : PMainWindow); cdecl; + +Var i : longint; + S : TStringList; + +begin + S:=TStringList.Create; + Try + GetFileSelection(Window^.FileList,S); + For I:=0 to S.Count-1 do + begin + For I:=0 to S.Count-1 do + SysUtils.DeleteFile(Window^.FDir+S[i]); + end; + Finally + If S.Count>0 then + RefreshFileView(Window); + S.Free; + end; +end; \ No newline at end of file diff --git a/docs/gtk4ex/filelist.inc b/docs/gtk4ex/filelist.inc new file mode 100644 index 0000000000..ba29769a22 --- /dev/null +++ b/docs/gtk4ex/filelist.inc @@ -0,0 +1,213 @@ + +Const + DefCompare : TGtkCListCompareFunc = Nil; + +Function FileCompareFunc(List:PGtkCList; Row1,Row2 : PGtkCListRow) : Longint; Cdecl; + +Var + SC : Longint; + +begin + SC:=List^.sort_column; + If SC in [2,3] then + begin + SC:=SC-2; + Result:=PLongint(Row1^.Data)[SC]-PLongint(Row2^.Data)[SC]; + end + Else + Result:=DefCompare(List,Row1,Row2); +end; + +Procedure DestroySortData(FSD : Pointer);cdecl; + +begin + FreeMem(FSD); +end; + +Procedure AddFileToList(List : PGtkCList; Info : TSearchRec); + +Var + Texts : Array[1..6] of AnsiString; + FSD : PLongint; + I : longint; + +begin + Texts[1]:=ExtractFileName(Info.Name); + Texts[2]:=ExtractFileExt(Info.Name); + Texts[3]:=FileSizeToString(Info.Size); + Texts[4]:=DateTimeToStr(FileDateToDateTime(Info.Time)); + Texts[5]:=FileAttrsToString(Info.Attr); + Texts[6]:=''; + i:=gtk_clist_append(List,@Texts[1]); + FSD:=GetMem(2*SizeOf(Longint)); + FSD[0]:=Info.Size; + FSD[1]:=Info.Time; + gtk_clist_set_row_data_full (List,I,FSD,@DestroySortData); +end; + +Function FillList(List : PGtkCList; Const Dir,Mask : String) : Integer; + +Var + Info : TSearchRec; + Size : Int64; + I : longint; + +begin + Result:=0; + Size:=0; + gtk_clist_freeze(List); + Try + gtk_clist_clear(List); + If FindFirst (AddTrailingSeparator(Dir)+Mask,faAnyFile,Info)=0 then + Repeat + Inc(Size,Info.Size); + AddFileToList(List,Info); + Inc(Result); + Until FindNext(Info)<>0; + FindClose(info); + finally + For I:=0 to 4 do + gtk_clist_set_column_width(List,i,gtk_clist_optimal_column_width(List,i)); + gtk_clist_thaw(List) + end; +end; + +Procedure ShowPopup(Widget : PGtkWidget; Event : PGdkEventButton; Window : PMainWindow);cdecl; + +begin + if (event^.thetype=GDK_BUTTON_PRESS) and (event^.button=3) then + begin + gtk_menu_popup(Window^.PMFiles,Nil,Nil,Nil,NIl,3,event^.time); + end; +end; + +Procedure FileColumnClick(List : PGtkCList;Column:gint; Window : PMainWindow);cdecl; + +Var + I : longint; + NS : TGtkSortType; + +begin + If Column<>List^.sort_column Then + begin + gtk_clist_set_sort_type(List,GTK_SORT_ASCENDING); + gtk_clist_set_sort_column(list,Column); + end + else + begin + If (List^.Sort_type=GTK_SORT_ASCENDING) Then + NS:=GTK_SORT_DESCENDING + else + NS:=GTK_SORT_ASCENDING; + gtk_clist_set_sort_type(List,NS); + end; + gtk_clist_sort(list); +end; + +Function NewFileList(MainWindow : PMainWindow) : PGtkClist; + +Const + Titles : Array[1..6] of pchar = ('Name','ext','Size','Date','Attributes',''); + +begin + MainWindow^.ListScrollWindow:=PGtkScrolledWindow(gtk_scrolled_window_new(Nil,Nil)); + gtk_scrolled_window_set_policy(MainWindow^.ListScrollWindow, + GTK_POLICY_AUTOMATIC, + GTK_POLICY_AUTOMATIC); + Result:=PGtkClist(Gtk_Clist_New_with_titles(6,@Titles)); + gtk_signal_connect(PgtkObject(Result),'button_press_event',TGtkSignalFunc(@ShowPopup),MainWindow); + gtk_signal_connect(PgtkObject(Result),'click_column',TGtkSignalFunc(@FileColumnClick),MainWindow); + gtk_Container_add(PGTKContainer(MainWindow^.ListScrollWindow),PGtkWidget(Result)); + gtk_clist_set_shadow_type(Result,GTK_SHADOW_ETCHED_OUT); + gtk_clist_set_column_justification(result,2,GTK_JUSTIFY_RIGHT); + gtk_clist_set_selection_mode(Result,GTK_SELECTION_MULTIPLE); + gtk_clist_set_auto_sort(Result,True); + If DefCompare=Nil then + DefCompare:=Result^.compare; + gtk_clist_set_compare_func(Result,TGtkCListCompareFunc(@FileCompareFunc)); +end; + +Procedure ToggleFileListTitles(Sender : PGtkCheckMenuItem;Window : PMainWindow);cdecl; + +begin + If active(Sender^)=0 then + gtk_clist_column_titles_show(Window^.FileList) + else + gtk_clist_column_titles_hide(Window^.FileList) +end; + +Procedure ToggleFileListColumns(Sender : PGtkCheckMenuItem;Window : PMainWindow);cdecl; + +Var Col : Longint; + +begin + With Window^ do + If Sender=MIShowExt Then + Col:=1 + else if Sender=MiShowSize Then + Col:=2 + else if Sender=MIShowDate then + Col:=3 + else + Col:=4; + gtk_clist_set_column_visibility(Window^.FileList,Col,(Active(Sender^)=0)); +end; + +Procedure GetFileSelection (List : PGtkClist; Selection : TStrings); + +Var + SList : PGList; + Index : Longint; + P : PChar; + +begin + Selection.Clear; + Slist:=List^.Selection; + While SList<>nil do + begin + Index:=Longint(SList^.Data); + gtk_clist_get_text(List,Index,0,@p); + Selection.Add(StrPas(p)); + SList:=g_list_next(SList); + end; +end; + +Function GetFileFirstSelection (List : PGtkClist) : String; + +Var + SList : PGList; + Index : Longint; + P : PChar; + +begin + REsult:=''; + Slist:=List^.Selection; + If SList<>nil then + begin + Index:=Longint(SList^.Data); + gtk_clist_get_text(List,Index,0,@p); + Result:=StrPas(p); + end; +end; + +Function GetFileSelectionCount (List : PGtkClist) : Longint; + +Var + SList : PGList; + +begin + Slist:=List^.Selection; + Result:=0; + While SList<>nil do + begin + Inc(Result); + SList:=g_list_next(SList); + end; +end; + +Procedure RefreshFileView(Window : PMainWindow); + +begin + With Window^ do + FillList(FileList,FDir,FMask); +end; \ No newline at end of file diff --git a/docs/gtk4ex/filemask.png b/docs/gtk4ex/filemask.png new file mode 100644 index 0000000000000000000000000000000000000000..f87c38c33178e751426b5361a8d57dd44f059628 GIT binary patch literal 2746 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 literal 0 HcmV?d00001 diff --git a/docs/gtk4ex/fileprops.png b/docs/gtk4ex/fileprops.png new file mode 100644 index 0000000000000000000000000000000000000000..11723b151bb94ad6e72730f37a8f9ba464615b21 GIT binary patch literal 5170 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 literal 0 HcmV?d00001 diff --git a/docs/gtk4ex/frmabout.pp b/docs/gtk4ex/frmabout.pp new file mode 100644 index 0000000000..b7c6246caf --- /dev/null +++ b/docs/gtk4ex/frmabout.pp @@ -0,0 +1,66 @@ +unit frmabout; + +{$mode objfpc} + +Interface + +uses glib,gdk,gtk; + +Type + TAboutForm = Record + Window : PGtkDialog; + OkButton : PgtkButton; + InfoLabel : PGtkLabel; + end; + PAboutForm = ^TAboutForm; + +Function NewAboutForm : PAboutForm; +Procedure ShowAboutForm(Form : PAboutForm); + +Implementation + +Const + SInfo : PChar = 'File explorer demo'#10'Florian Klaempfl'#10'Michael Van Canneyt'; + SAboutTitle : Pchar = 'About File explorer'; + +procedure DestroyAbout(Widget : PGtkWidget; About : PAboutForm);cdecl; + +begin + Dispose(About); +end; + +Function NewAboutForm : PAboutForm; + +begin + Result:=New(PAboutForm); + With Result^ do + begin + Window:=PgtkDialog(gtk_dialog_new); + gtk_window_set_modal(PgtkWindow(Window),True); + gtk_window_set_title(PgtkWindow(Window),SAboutTitle); + gtk_widget_set_usize(PGtkWidget(Window),250,150); + gtk_window_set_policy(PgtkWindow(Window),0,0,0); + gtk_window_set_position(PGtkWindow(Window),GTK_WIN_POS_CENTER); + OkButton:=PGtkButton(gtk_button_new_with_label(' Ok ')); + gtk_box_pack_start(PgtkBox(Window^.action_area),PGtkWidget(Okbutton),False,False,5); + gtk_window_set_focus(PGtkWindow(Window),PGtkWidget(OkButton)); + gtk_widget_show(PGtkWidget(OkButton)); + InfoLabel:=PgtkLabel(gtk_label_new(SInfo)); + gtk_box_pack_start(PGtkBox(Window^.vbox),PGtkWidget(InfoLabel),True,True,10); + gtk_widget_show(PGtkWidget(InfoLabel)); + gtk_signal_connect(PGtkObject(Window),'destroy', + TGTKSignalFunc(@DestroyAbout),Result); + gtk_signal_connect_object(PgtkObject(OKButton),'clicked', + GTK_SIGNAL_FUNC(@gtk_widget_destroy), + PGTKOBJECT(Window)); + end; +end; + +Procedure ShowAboutForm(Form : PAboutForm); + +begin + gtk_window_set_modal(PgtkWindow(Form^.Window),True); + gtk_widget_show(PgtkWidget(Form^.Window)); +end; + +end. \ No newline at end of file diff --git a/docs/gtk4ex/frmmain.pp b/docs/gtk4ex/frmmain.pp new file mode 100644 index 0000000000..8ef07ca9b7 --- /dev/null +++ b/docs/gtk4ex/frmmain.pp @@ -0,0 +1,244 @@ +unit frmmain; + +{$mode objfpc} + +Interface + +Uses gtk,gdk,glib,sysutils,classes; + +Type + TMainWindow = Record + FDir, + FMask : String; + Window : PGtkWindow; + Menu : PGtkMenuBar; + Toolbar : PGtkToolBar; + DirTree : PGtkTree; + FileList : PGtkClist; + Pane : PGtkPaned; + StatusBar : PGtkStatusBar; + FilesHeader,DirHeader : PGtkLabel; + // helper objects - Menu + Accel : PGtkAccelGroup; + MFile, + MView, + MColumns, + MHelp, + // Main menu items + PMFiles : PGtkMenu; + MIFile, + MIFileProperties, + MIFileDelete, + MIExit, + MIColumns, + MIMask, + MIAbout, + MIHelp : PGtkMenuItem; + MIShowTitles, + MIShowExt, + MIShowSize, + MiShowDate, + MIShowAttrs : PGtkCheckMenuItem; + // Files PopupMenu Items: + PMIFileProperties, + PMIFileDelete : PGtkMenuItem; + // Packing boxes + VBox, + LeftBox, + RightBox : PGtkBox; + // Scroll boxes + TreeScrollWindow, + ListScrollWindow : PGtkScrolledWindow; + // Tree root node. + RootNode : PGtkTreeItem; + + end; + PMainWindow = ^TMainWindow; + +Function NewMainForm : PMainWindow; +Function NewMainMenu(MainWindow : PMainWindow) : PGtkMenuBar; +Function NewToolbar(MainWindow : PMainWindow) : PGtkToolbar; +Function NewDirtree(MainWindow : PMainWindow) : PGtkTree; +Function NewFileList(MainWindow : PMainWindow) : PGtkClist; +Procedure ShowDir (Window : PMainWindow; Dir : String); +Function NewFilePopupMenu (MainWindow : PMainWindow) : PGtkMenu; + +Implementation + +uses menus,futils,frmabout,fxbitmaps,frmprops,frmmask; + +Const + SFileExplorer : PChar = 'File explorer'; + SFilesindir = 'Files in directory %s'; + SDirTree : Pchar = 'Directory tree'; + +{$i filelist.inc} +{$i dirlist.inc} +{$i factions.inc} + +procedure destroy(widget : pGtkWidget ; Window : PMainWindow); cdecl; +begin + gtk_clist_clear(Window^.FileList); + dispose(Window); + gtk_main_quit(); +end; + +procedure DoAbout(widget : pGtkWidget ; data: pgpointer ); cdecl; +begin + ShowAboutForm(NewAboutform); +end; + +Procedure ApplyMask(Mask : String; Data : Pointer); + +begin + PMainWindow(data)^.FMask:=Mask; + RefreshFileView(PMainWindow(Data)); +end; + +procedure DoMask(Widget : PGtkWidget ; MainForm : PMainWindow ); cdecl; + +Var + S : AnsiString; + +begin + With NewMaskForm^ do + begin + S:=MainForm^.FMask; + gtk_entry_set_text(EMask,PChar(S)); + CallBack:=@ApplyMask; + CallBackData:=MainForm; + gtk_widget_show_all(PgtkWidget(Window)); + end; +end; + +Function NewMainForm : PMainWindow; + +begin + Result:=New(PMainWindow); + With Result^ do + begin + FMask:='*.*'; + Window:=PgtkWindow(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + gtk_window_set_title(Window,SFileExplorer); + gtk_widget_set_usize(PgtkWidget(Window),640,480); + gtk_signal_connect (PGTKOBJECT (window), 'destroy', + GTK_SIGNAL_FUNC (@destroy), Result); + gtk_widget_realize(PgtkWidget(window)); + Menu:=NewMainMenu(Result); + ToolBar:=NewToolbar(Result); + Pane:=PgtkPaned(gtk_hpaned_new); + StatusBar:=PgtkStatusBar(gtk_statusbar_new); + FileList:=NewFileList(Result); + DirTree:=NewDirtree(Result); + PMFiles:=NewFilePopupMenu(Result); + FilesHeader:=PgtkLabel(gtk_label_new(pchar(SFilesInDir))); + DirHeader:=PgtkLabel(gtk_label_new(pchar(SDirTree))); + LeftBox:=PGtkBox(gtk_vbox_new(false,0)); + gtk_box_pack_start(Leftbox,PGtkWidget(DirHeader),False,False,0); + gtk_box_pack_start(Leftbox,PgtkWidget(TreeScrollWindow),true,True,0); + gtk_paned_add1(pane,PGtkWidget(Leftbox)); + RightBox:=PGtkBox(gtk_vbox_new(false,0)); + gtk_box_pack_start(Rightbox,PGtkWidget(FilesHeader),False,False,0); + gtk_box_pack_start(Rightbox,PGtkWidget(ListScrollWindow),true,True,0); + gtk_paned_add2(pane,PGtkWidget(Rightbox)); + VBox:=PGtkBox(gtk_vbox_new(false,0)); + gtk_container_add(PGtkContainer(Window),PgtkWidget(VBox)); + gtk_box_pack_start(vbox,PGtkWidget(Menu),False,False,0); + gtk_widget_show_all(PGtkWidget(vbox)); + gtk_box_pack_start(vbox,PGtkWidget(ToolBar),False,False,0); + gtk_box_pack_start(vbox,PGtkWidget(Pane),true,true,0); + gtk_box_pack_start(vbox,PGtkWidget(StatusBar),false,false,0); + end; +end; + + + +Function NewMainMenu(MainWindow : PMainWindow) : PGtkMenuBar; + +begin + With MainWindow^ do + begin + Result:=pgtkmenubar(gtk_menu_bar_new); + Accel:=gtk_accel_group_new; + gtk_window_add_accel_group(Window,accel); + MFile:=AddMenuToMenuBar(Result,accel,'_File',Nil,Nil,False,MIFile); + MIFileProperties:=AddItemToMenu(MFile,accel,'_Properties','p',TgtkSignalFunc(@DoProperties),MainWindow); + MIFileDelete:=AddItemToMenu(MFile,accel,'_Delete','',TgtkSignalFunc(@DeleteFile),MainWindow); + AddSeparatorToMenu(MFile); + MIExit:=AddItemToMenu(MFile,accel,'E_xit','x',TgtkSignalFunc(@destroy),MainWindow); + MView:=AddMenuToMenuBar(Result,accel,'_View',Nil,Nil,False,MIFile); + MIShowTitles:=AddCheckItemToMenu(MView,accel,'Hide titles','',TgtkSignalFunc(@ToggleFileListTitles),MainWindow); + MIColumns:=AddItemToMenu(MView,accel,'Hide columns','',Nil,MainWindow); + MIMask:=AddItemToMenu(MView,accel,'File Mask','',TGtkSignalFunc(@DoMask),MainWindow); + MColumns:=PgtkMenu(gtk_menu_new); + gtk_menu_item_set_submenu(MIColumns, PgtkWidget(MColumns)); + MIShowExt:=AddCheckItemToMenu(MColumns,accel,'Extension','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow); + MIShowSize:=AddCheckItemToMenu(MColumns,accel,'Size','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow); + MIShowDate:=AddCheckItemToMenu(MColumns,accel,'Date','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow); + MIShowAttrs:=AddCheckItemToMenu(MColumns,accel,'Attributes','',TgtkSignalFunc(@ToggleFileListColumns),MainWindow); + MHelp:=AddMenuToMenuBar(Result,accel,'_Help',Nil,Nil,True,MIHelp); + MIAbout:=AddItemToMenu(MHelp,accel,'_About','',TgtkSignalFunc(@DoAbout),Nil); + gtk_widget_show(PgtkWidget(result)); + end; +end; + +Function NewToolbar (MainWindow : PMainWindow) : PGtkToolbar; + +begin + Result:=pGtkToolBar(gtk_toolbar_new(GTK_ORIENTATION_HORIZONTAL,GTK_TOOLBAR_ICONS)); + gtk_toolbar_append_item(result, + Nil, + 'File Properties', + nil, + CreateWidgetFromXPm(PgtkWidget(MainWindow^.Window),@PropertiesXPM), + TgtkSignalFunc(@DoProperties), + MainWindow); + gtk_toolbar_append_item(result, + Nil, + 'Delete File', + Nil, + CreateWidgetFromXPm(PgtkWidget(MainWindow^.Window),@DeleteXPM), + TgtkSignalFunc(@DeleteFile), + MainWindow); +end; + + + +Procedure ShowDir (Window : PMainWindow; Dir : String); + +begin + With Window^ do + begin + FDir:=Dir; + FillList(FileList,Dir,FMask); + gtk_label_set_text(FilesHeader,pchar(Format(SFilesInDir,[Dir]))); + end; +end; + +Procedure PMFilesActivate(Widget : PGtkWidget; Window : PMainWindow); cdecl; + +Var State : TGtkStateType; + +begin + if GetFileSelectionCount(Window^.FileList)>1 then + State:=GTK_STATE_INSENSITIVE + else + State:=GTK_STATE_Normal; + gtk_widget_set_state(PgtkWidget(Window^.PMIFileProperties),State); +end; + + +Function NewFilePopupMenu (MainWindow : PMainWindow) : PGtkMenu; + +begin + result:=PGtkMenu(gtk_menu_new); + gtk_signal_connect(PGtkObject(result),'show', + TGtkSignalFunc(@PMFilesActivate),MainWindow); + With MainWindow^ do + begin + PMIFileProperties:=AddItemToMenu(Result,Accel,'_Properties','',TgtkSignalFunc(@DoProperties),MainWindow); + PMIFileDelete:=AddItemToMenu(Result,Accel,'_Delete','d',TgtkSignalFunc(@DeleteFile),MainWindow); + end; +end; + +end. \ No newline at end of file diff --git a/docs/gtk4ex/frmmask.pp b/docs/gtk4ex/frmmask.pp new file mode 100644 index 0000000000..836789354b --- /dev/null +++ b/docs/gtk4ex/frmmask.pp @@ -0,0 +1,88 @@ +unit frmmask; + +{$mode objfpc} + +Interface + +uses glib,gdk,gtk; + +Type + TMaskCallBack = Procedure (Mask : String; Data : Pointer); + TMaskForm = Record + Window : PGtkDialog; + EMask : PGtkEntry; + LEMAsk : PGtkLabel; + HBox : PGtkBox; + OKButton, + CancelButton : PGtkButton; + Mask : ShortString; + CallBack : TMaskCallBack; + CallBackData : Pointer; + end; + PMaskForm = ^TMaskForm; + +Function NewMaskForm : PMaskForm; + +Implementation + +Const + SEnterMask : PChar = 'Enter new file mask'; + SNewMask : PChar = 'New mask'; + SOK : PChar = ' OK '; + SCancel : PChar = ' Cancel '; + +Procedure ApplyMask(Widget : PGtkWidget; Window : PMaskForm);cdecl; + +begin + With Window^ do + begin + Mask:=StrPas(gtk_entry_get_text(EMask)); + If (CallBack<>Nil) then + CallBack(Mask,CallBackData); + end; +end; + +Procedure DestroyMaskForm(Widget : PGtkWidget; Window : PMaskForm);cdecl; + +begin + Dispose(Window); +end; + +Function NewMaskForm : PMaskForm; + +begin + Result:=New(PMaskForm); + With Result^ do + begin + Window:=PGtkDialog(gtk_dialog_new); + gtk_window_set_title(PgtkWindow(Window),SEnterMask); + gtk_widget_set_usize(PGtkWidget(Window),350,150); + gtk_window_set_policy(PgtkWindow(Window),0,0,0); + gtk_window_set_position(PGtkWindow(Window),GTK_WIN_POS_CENTER); + OKButton:=PGtkButton(gtk_button_new_with_label(SOK)); + CancelButton:=PGtkButton(gtk_button_new_with_label(SCancel)); + gtk_box_pack_end(PgtkBox(Window^.action_area),PGtkWidget(Okbutton),False,False,5); + gtk_box_pack_end(PgtkBox(Window^.action_area),PGtkWidget(Cancelbutton),False,False,5); + Emask:=PGtkEntry(gtk_entry_new_with_max_length(255)); + LEMask:=PGtkLabel(gtk_label_new(SNewMask)); + HBox:=PGtkBox(gtk_hbox_new(False,8)); + gtk_box_pack_start(PgtkBox(HBox),PGtkWidget(LEMask),True,False,0); + gtk_box_pack_start(PgtkBox(HBox),PGtkWidget(EMask),True,False,0); + gtk_box_pack_start(PGtkBox(Window^.vbox),PGtkWidget(HBox),True,True,10); + gtk_window_set_modal(PGtkWindow(Window),TRUE); + gtk_signal_connect(PgtkObject(OKButton),'clicked', + TGtkSignalFunc(@ApplyMask),Result); + gtk_signal_connect_object(PgtkObject(OKButton),'clicked', + GTK_SIGNAL_FUNC(@gtk_widget_destroy), + PGTKOBJECT(Window)); + gtk_signal_connect_object(PgtkObject(CancelButton),'clicked', + GTK_SIGNAL_FUNC(@gtk_widget_destroy), + PGTKOBJECT(Window)); + gtk_signal_connect(PgtkObject(Window),'destroy', + TGtkSignalFunc(@DestroyMaskForm),Result); + CallBack:=Nil; + CallBackdata:=Nil; + end; +end; + +end. \ No newline at end of file diff --git a/docs/gtk4ex/frmprops.pp b/docs/gtk4ex/frmprops.pp new file mode 100644 index 0000000000..dba24b9040 --- /dev/null +++ b/docs/gtk4ex/frmprops.pp @@ -0,0 +1,130 @@ +Unit frmprops; + +{$mode objfpc} + +Interface + +uses glib,gdk,gtk,sysutils; + +Const + NrTableLines = 8; + CheckBoxLineStart = 5; + + +Type + TFilePropertiesDialog = Record + Window : PgtkDialog; + Table : PGtkTable; + OkButton : PGtkButton; + Labels : Array[0..1,0..NrTableLines] of PGtkLabel; + CheckBoxes : Array[CheckBoxLineStart..NrTableLines] of PgtkCheckButton; + end; + PFilePropertiesDialog = ^TFilePropertiesDialog; + +Function NewFilePropertiesDialog(FileName : String) : PFilePropertiesDialog; +Procedure ShowFilePropertiesDialog(Dialog : PFilePropertiesDialog); + +Implementation + +uses Futils; + +Const + SPropsTitle : PChar = 'File properties'; + SOk : PChar = ' OK '; + SFile = ' File.'; + LabelTexts : Array[0..NrTableLines] of Pchar = ( + 'Name', + 'Directory', + 'Type', + 'Size', + 'Date', + 'Attributes', + '', + '', + '' + ); + + CheckBoxTexts : Array[CheckBoxLineStart..NrTableLines] of Pchar = ( + 'Read-only', + 'Archive', + 'Hidden', + 'System' + ); + +procedure DestroyPropDialog(Widget : PGtkWidget; Dlg : PFilePropertiesDialog);cdecl; + +begin + Dispose(Dlg); +end; + + +Function NewFilePropertiesDialog(FileName : String) : PFilePropertiesDialog; + +Const + CheckAttrs : Array [CheckBoxLineStart..NrTableLines] of Integer + = (faReadOnly,faArchive,faHidden,faSysFile); + +Var + Info : TSearchRec; + I : Longint; + +begin + Result:=New(PFilePropertiesDialog); + With Result^ do + begin + Window:=PgtkDialog(gtk_dialog_new); + gtk_window_set_title(PgtkWindow(Window),SPropsTitle); + gtk_window_set_modal(PgtkWindow(Window),True); + gtk_window_set_policy(PgtkWindow(Window),0,0,0); + gtk_window_set_position(PGtkWindow(Window),GTK_WIN_POS_CENTER); + OkButton:=PGtkButton(gtk_button_new_with_label(SOK)); + gtk_box_pack_start(PgtkBox(Window^.action_area),PGtkWidget(Okbutton),False,False,5); + gtk_window_set_focus(PGtkWindow(Window),PGtkWidget(OkButton)); + gtk_widget_show(PGtkWidget(OkButton)); + Table:=PgtkTable(gtk_table_new(NrTableLines+1,2,TRUE)); + gtk_box_pack_start(PGtkBox(Window^.vbox),PGtkWidget(Table),True,True,10); + For I:=0 to NrTableLines do + begin + Labels[0,i]:=PGtkLabel(gtk_label_new(LabelTexts[i])); + gtk_label_set_justify(Labels[0,I],GTK_JUSTIFY_RIGHT); + gtk_table_attach_defaults(Table,PgtkWidget(Labels[0,I]),0,1,I,I+1); + end; + For I:=0 to CheckboxLineStart-1 do + begin + Labels[1,i]:=PGtkLabel(gtk_label_new('')); + gtk_label_set_justify(Labels[1,I],GTK_JUSTIFY_LEFT); + gtk_table_attach_defaults(Table,PgtkWidget(Labels[1,I]),1,2,I,I+1); + end; + For I:=CheckboxLineStart to NrTableLines do + begin + checkBoxes[i]:=PgtkCheckButton(gtk_check_button_new_with_label(CheckBoxTexts[I])); + gtk_widget_set_state(PGtKWidget(CheckBoxes[i]),GTK_STATE_INSENSITIVE); + gtk_table_attach_defaults(Table,PgtkWidget(CheckBoxes[i]),1,2,I,I+1); + end; + gtk_label_set_text(Labels[1,0],PChar(ExtractFileName(FileName))); + gtk_label_set_text(Labels[1,1],PChar(ExtractFilePath(FileName))); + gtk_label_set_text(Labels[1,2],PChar(ExtractFileExt(FileName)+SFile)); + If FindFirst(FileName,faAnyFile,Info)=0 Then + begin + gtk_label_set_text(Labels[1,3],PChar(FileSizeToString(Info.Size))); + gtk_label_set_text(Labels[1,4],PChar(DateTimeToStr(FileDateToDateTime(Info.Time)))); + For I:=CheckboxLineStart to NrTableLines do + If (CheckAttrs[i] and Info.Attr)=CheckAttrs[i] then + gtk_toggle_button_set_active(PgtkToggleButton(CheckBoxes[I]),True); + FindClose(Info); + end; + gtk_signal_connect(PGtkObject(Window),'destroy', + TGTKSignalFunc(@DestroyPropDialog),Result); + gtk_signal_connect_object(PgtkObject(OKButton),'clicked', + GTK_SIGNAL_FUNC(@gtk_widget_destroy), + PGTKOBJECT(Window)); + end; +end; + +Procedure ShowFilePropertiesDialog(Dialog : PFilePropertiesDialog); + +begin + gtk_widget_show_all(PgtkWidget(Dialog^.Window)); +end; + +end. \ No newline at end of file diff --git a/docs/gtk4ex/futils.pp b/docs/gtk4ex/futils.pp new file mode 100644 index 0000000000..8ceada5303 --- /dev/null +++ b/docs/gtk4ex/futils.pp @@ -0,0 +1,92 @@ +unit futils; + +{$mode objfpc} +{$h+} + +Interface + +Const +{$ifdef win32} + PathSeparator='\'; +{$else} + PathSeparator='/'; +{$endif} + + +Function StripTrailingSeparator(Const Dir : String) : String; +Function AddTrailingSeparator(Const Dir : String) : String; +Function FileSizeToString(Size: Int64) : String; +Function FileAttrsToString(FileAttrs : Integer) : String; + +Implementation + +Uses sysutils; + +Function StripTrailingSeparator(Const Dir : String) : String; + +Var + L : Integer; + +begin + Result:=Dir; + L:=Length(result); + If (L>1) and (Result[l]=PathSeparator) then + SetLength(Result,L-1); +end; + +Function AddTraiLingSeparator(Const Dir : String) : String; + +Var + L : Integer; + +begin + Result:=Dir; + L:=Length(Result); + If (L>0) and (Result[l]<>PathSeparator) then + Result:=Result+PathSeparator; +end; + +Function FileSizeToString(Size: Int64) : String; + +Const + Sizes : Array [0..4] of String = + ('Bytes','Kb','Mb','Gb','Tb'); +Var + F : Double; + I : longint; + +begin + If Size>1024 Then + begin + F:=Size; + I:=0; + While (F>1024) and (I<4) do + begin + F:=F / 1024; + Inc(i); + end; + Result:=Format('%4.2f %s',[F,Sizes[i]]); + end + else + Result:=Format('%d %s',[Size,Sizes[0]]); +end; + +Function FileAttrsToString(FileAttrs : Integer) : String; + +Const + Attrs : Array[1..4] of integer = + (faArchive,faReadOnly,faHidden,faSysfile); + AttrChars : Array[1..4] of char = + ('A','R','H','S'); + +Var + i : longint; + +begin + Result:=''; + For I:=1 to 4 do + If (Attrs[i] and FileAttrs)=Attrs[i] then + Result:=Result+AttrChars[i]; +end; + +end. \ No newline at end of file diff --git a/docs/gtk4ex/fx.pp b/docs/gtk4ex/fx.pp new file mode 100644 index 0000000000..6965f3496f --- /dev/null +++ b/docs/gtk4ex/fx.pp @@ -0,0 +1,14 @@ +program fx; + +uses glib,gdk,gtk,frmmain,sysutils; + +Var + MainWindow : PMainWindow; + +begin + gtk_init(@argc,@argv); + MainWindow:=NewMainForm; + gtk_widget_show_all(PGtkWidget(MainWindow^.Window)); + ShowDir(mainwindow,Extractfilepath(Paramstr(0)){'/usr/bin/'}); + gtk_main; +end. \ No newline at end of file diff --git a/docs/gtk4ex/fxbitmaps.pp b/docs/gtk4ex/fxbitmaps.pp new file mode 100644 index 0000000000..a2cd7286dd --- /dev/null +++ b/docs/gtk4ex/fxbitmaps.pp @@ -0,0 +1,78 @@ +Unit fxbitmaps; + +{$mode objfpc} + +Interface + +uses glib,gdk,gtk; + +Const + DeleteXpmHeight=16; + DeleteXpmColors=2; + DeleteXpmArraySize=DeleteXpmHeight+DeleteXpmColors+1; + DeleteXpm : Array[1..DeleteXpmArraySize] of Pchar = ( + '16 16 2 1', { 16x16 bitmap using 2 colors, 1 char per color} + '. c #000000', { First color: Black } + '# c None', { Second color : Transparent} + '################', { The bitmap } + '################', + '##...#########.#', + '##....######..##', + '###....####..###', + '#####...##..####', + '######.....#####', + '#######...######', + '######.....#####', + '#####...##..####', + '####...####..###', + '###...######.###', + '##....#######.##', + '##...###########', + '###.##########.#', + '################' + ); + + PropertiesXpmHeight = 16; + PropertiesXpmColors = 4; + PropertiesXpmArraySize = PropertiesXpmHeight+PropertiesXpmColors+1; + PropertiesXpm : Array [1..PropertiesXpmArraySize] of PChar = ( + '16 16 4 1', { 16x16 bitmap using 2 colors, 1 char per color} + '. c #000000', { First color : Black } + '# c #000080', { Second color : Light Blue } + 'a c None', { Third color : Transparent } + 'b c #f8fcf8', { Last color : greyish } + 'aaaaaaaaaaaaaaaa', + 'aaaaaaa......a##', + 'aaaaaa.aaaaaa.##', + 'aaaaa.a.aaaaaa##', + '.....a.a.aaaaa##', + '.bb.a.a.a.aaa.##', + '.b.a.b.a.a...a##', + '.b..bbb.a.b.aaaa', + '.bbbbbbb.bb.aaaa', + '.bbbbbbbbbb.aaaa', + '.b..b.....b.aaaa', + '.bbbbbbbbbb.aaaa', + '.b..b.....b.aaaa', + '.bbbbbbbbbb.aaaa', + '............aaaa', + 'aaaaaaaaaaaaaaaa' +); + +function CreateWidgetFromXPM (Window : PGtkWidget; Data : PPChar) : PgtkWidget; + +Implementation + +function CreateWidgetFromXPM (Window : PGtkWidget; Data : PPChar) : PGtkWidget; + +Var + mask : PGdkBitmap; + pixmap : PGdkPixMap; + +begin + pixmap:=gdk_pixmap_create_from_xpm_d(window^.window,@mask,nil,ppgchar(Data)); + Result:=gtk_pixmap_new(Pixmap,Mask); + gtk_widget_show(Result); +end; + +end. diff --git a/docs/gtk4ex/mainwin.png b/docs/gtk4ex/mainwin.png new file mode 100644 index 0000000000000000000000000000000000000000..115eb174e0e1a7961726f3da4954c7ce627a86ff GIT binary patch literal 20275 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 then + gtk_widget_add_accelerator(PGtkWidget(MenuItem),'activate_item', + Shortcuts,Key, + GDK_MOD1_MASK,GTK_ACCEL_LOCKED); + Result:=PGtkMenu(gtk_menu_new); + If CallBack<>Nil then + gtk_signal_connect(PGtkObject(result),'activate', + CallBack,CallBackdata); + gtk_widget_show(PgtkWidget(MenuItem)); + gtk_menu_item_set_submenu(MenuItem, PgtkWidget(Result)); + gtk_menu_bar_append(MenuBar,PgtkWidget(MenuItem)); +end; + +Function AddItemToMenu (Menu : PGtkMenu; + ShortCuts : PGtkAccelGroup; + Caption : AnsiString; + ShortCut : AnsiString; + CallBack : TgtkSignalFunc; + CallBackdata : Pointer + ) : PGtkMenuItem; + +Var + Key,Modifiers : guint; + LocalAccelGroup : PGtkAccelGroup; + TheLabel : PGtkLabel; + +begin + Result:=pgtkmenuitem(gtk_menu_item_new_with_label('')); + TheLabel:=GTK_LABEL(GTK_BIN(Result)^.child); + Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption)); + If Key<>0 then + begin +{ $ifndef win32} + LocalAccelGroup:=gtk_menu_ensure_uline_accel_group(Menu); +{ $endif} + gtk_widget_add_accelerator(PGtkWidget(result),'activate_item', + LocalAccelGroup,Key, + 0,TGtkAccelFlags(0)); + end; + gtk_menu_append(Menu,pgtkWidget(result)); + If (ShortCut<>'') and (ShortCuts<>Nil) then + begin + gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers); + gtk_widget_add_accelerator(PGtkWidget(result),'activate_item', + ShortCuts,Key, + modifiers, GTK_ACCEL_VISIBLE); + end; + If CallBack<>Nil then + gtk_signal_connect(PGtkObject(result),'activate', + CallBack,CallBackdata); + gtk_widget_show(PgtkWidget(result)); +end; + +Function AddCheckItemToMenu (Menu : PGtkMenu; + ShortCuts : PGtkAccelGroup; + Caption : AnsiString; + ShortCut : AnsiString; + CallBack : TgtkSignalFunc; + CallBackdata : Pointer + ) : PGtkCheckMenuItem; + +Var + Key,Modifiers : guint; + LocalAccelGroup : PGtkAccelGroup; + TheLabel : PGtkLabel; + +begin + Result:=pgtkcheckmenuitem(gtk_check_menu_item_new_with_label(PChar(Caption))); + gtk_check_menu_item_set_show_toggle(Result,True); + gtk_menu_append(Menu,pgtkWidget(result)); + If (ShortCut<>'') and (ShortCuts<>Nil) then + begin + gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers); + gtk_widget_add_accelerator(PGtkWidget(result),'activate_item', + ShortCuts,Key, + modifiers, GTK_ACCEL_VISIBLE); + end; + If CallBack<>Nil then + gtk_signal_connect(PGtkObject(result),'toggled', + CallBack,CallBackdata); + gtk_widget_show(PgtkWidget(result)); +end; + +Function AddImageItemToMenu (Menu : PGtkMenu; + ShortCuts : PGtkAccelGroup; + Caption : AnsiString; + ShortCut : AnsiString; + Bitmap : AnsiString; + CallBack : TgtkSignalFunc; + CallBackdata : Pointer + ) : PGtkMenuItem; + +Var + Key,Modifiers : guint; + LocalAccelGroup : PGtkAccelGroup; + TheLabel : PGtkLabel; + Image : PGtkPixmap; + hbox : PGtkHBox; + pixmap : PGdkPixmap; + BitMapdata : PGdkBitmap; + +begin + Result:=pgtkmenuitem(gtk_menu_item_new); + hbox:=PGtkHBox(gtk_hbox_new(false,0)); + gtk_container_add(pgtkcontainer(result),pgtkWidget(hbox)); + pixmap:=gdk_pixmap_create_from_xpm(Nil,@BitmapData,Nil,pchar(BitMap)); + Image := PgtkPixMap(gtk_pixmap_new(Pixmap,BitmapData)); + gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(image),false,false,0); + TheLabel:=PgtkLabel(gtk_label_new('')); + gtk_box_pack_start(PGtkBox(hbox),pgtkWidget(TheLabel),True,True,0); + Key:=gtk_label_parse_uline(TheLabel,Pchar(Caption)); + If Key<>0 then + begin +{ $ifndef win32} + LocalAccelGroup:=gtk_menu_ensure_uline_accel_group(Menu); +{ $endif} + gtk_widget_add_accelerator(PGtkWidget(result),'activate_item', + LocalAccelGroup,Key, + 0,TGtkAccelFlags(0)); + end; + gtk_menu_append(Menu,pgtkWidget(result)); + If (ShortCut<>'') and (ShortCuts<>Nil) then + begin + gtk_accelerator_parse (pchar(ShortCut), @key, @modifiers); + gtk_widget_add_accelerator(PGtkWidget(result),'activate_item', + ShortCuts,Key, + modifiers, GTK_ACCEL_VISIBLE); + end; + If CallBack<>Nil then + gtk_signal_connect(PGtkObject(result),'activate', + CallBack,CallBackdata); + gtk_widget_show_all(PgtkWidget(result)); +end; + +Function AddSeparatorToMenu(Menu : PgtkMenu) : PgtkMenuItem; + +begin + Result:=pgtkmenuitem(gtk_menu_item_new()); + gtk_menu_append(Menu,pgtkWidget(result)); + gtk_widget_show(PgtkWidget(result)); +end; + +end. \ No newline at end of file diff --git a/docs/gtk4ex/properties.xpm b/docs/gtk4ex/properties.xpm new file mode 100644 index 0000000000..2a787264e7 --- /dev/null +++ b/docs/gtk4ex/properties.xpm @@ -0,0 +1,27 @@ +/* XPM */ +static char *properties[] = { +/* width height num_colors chars_per_pixel */ +" 16 16 4 1", +/* colors */ +". c #000000", +"# c #000080", +"a c #c0c0c0", +"b c #f8fcf8", +/* pixels */ +"aaaaaaaaaaaaaaaa", +"aaaaaaa......a##", +"aaaaaa.aaaaaa.##", +"aaaaa.a.aaaaaa##", +".....a.a.aaaaa##", +".bb.a.a.a.aaa.##", +".b.a.b.a.a...a##", +".b..bbb.a.b.aaaa", +".bbbbbbb.bb.aaaa", +".bbbbbbbbbb.aaaa", +".b..b.....b.aaaa", +".bbbbbbbbbb.aaaa", +".b..b.....b.aaaa", +".bbbbbbbbbb.aaaa", +"............aaaa", +"aaaaaaaaaaaaaaaa" +};