mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-22 20:59:26 +02:00
1330 lines
48 KiB
ObjectPascal
1330 lines
48 KiB
ObjectPascal
{ $Id$}
|
|
{
|
|
*****************************************************************************
|
|
* GtkWSDialogs.pp *
|
|
* --------------- *
|
|
* *
|
|
* *
|
|
*****************************************************************************
|
|
|
|
*****************************************************************************
|
|
* *
|
|
* This file is part of the Lazarus Component Library (LCL) *
|
|
* *
|
|
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
|
|
* for details about the copyright. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
|
* *
|
|
*****************************************************************************
|
|
}
|
|
unit GtkWSDialogs;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$ifdef gtk2}
|
|
Gtk2, Glib2, gdk2, pango,
|
|
{$else}
|
|
Gtk, gdk, Glib,
|
|
{$endif}
|
|
SysUtils, Classes,
|
|
Controls, Graphics, Dialogs, ExtDlgs,
|
|
LCLType, LMessages, InterfaceBase, LCLStrConsts, LCLProc, FileUtil,
|
|
WSDialogs, WSLCLClasses,
|
|
GtkInt, GtkProc, GtkWSControls, GtkExtra, GtkDef, GtkGlobals;
|
|
|
|
type
|
|
|
|
{ TGtkWSCommonDialog }
|
|
|
|
TGtkWSCommonDialog = class(TWSCommonDialog)
|
|
public
|
|
class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
|
|
class procedure SetSizes(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
|
|
published
|
|
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
|
|
class procedure ShowModal(const ACommonDialog: TCommonDialog); override;
|
|
class procedure DestroyHandle(const ACommonDialog: TCommonDialog); override;
|
|
end;
|
|
|
|
{ TGtkWSFileDialog }
|
|
|
|
TGtkWSFileDialog = class(TWSFileDialog)
|
|
protected
|
|
class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
|
|
published
|
|
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
|
|
end;
|
|
|
|
{ TGtkWSOpenDialog }
|
|
|
|
TGtkWSOpenDialog = class(TWSOpenDialog)
|
|
protected
|
|
class function CreateOpenDialogFilter(OpenDialog: TOpenDialog; SelWidget: PGtkWidget): string; virtual;
|
|
class procedure CreateOpenDialogHistory(OpenDialog: TOpenDialog; SelWidget: PGtkWidget); virtual;
|
|
class procedure CreatePreviewDialogControl(PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget); virtual;
|
|
published
|
|
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
|
|
end;
|
|
|
|
{ TGtkWSSaveDialog }
|
|
|
|
TGtkWSSaveDialog = class(TWSSaveDialog)
|
|
published
|
|
end;
|
|
|
|
{ TGtkWSSelectDirectoryDialog }
|
|
|
|
TGtkWSSelectDirectoryDialog = class(TWSSelectDirectoryDialog)
|
|
published
|
|
end;
|
|
|
|
{ TGtkWSColorDialog }
|
|
|
|
TGtkWSColorDialog = class(TWSColorDialog)
|
|
protected
|
|
class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
|
|
published
|
|
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
|
|
end;
|
|
|
|
{ TGtkWSColorButton }
|
|
|
|
TGtkWSColorButton = class(TWSColorButton)
|
|
published
|
|
end;
|
|
|
|
{ TGtkWSFontDialog }
|
|
|
|
TGtkWSFontDialog = class(TWSFontDialog)
|
|
protected
|
|
class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual;
|
|
published
|
|
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
|
|
end;
|
|
|
|
// forward declarations
|
|
|
|
procedure UpdateDetailView(OpenDialog: TOpenDialog);
|
|
function gtkDialogHelpclickedCB(widget: PGtkWidget; data: gPointer): GBoolean; cdecl;
|
|
|
|
implementation
|
|
|
|
{-------------------------------------------------------------------------------
|
|
procedure UpdateDetailView
|
|
Params: OpenDialog: TOpenDialog
|
|
Result: none
|
|
|
|
Shows some OS dependent information about the current file
|
|
-------------------------------------------------------------------------------}
|
|
procedure UpdateDetailView(OpenDialog: TOpenDialog);
|
|
var
|
|
FileDetailLabel: PGtkWidget;
|
|
Filename, OldFilename, Details: String;
|
|
Widget: PGtkWidget;
|
|
begin
|
|
//DebugLn(['UpdateDetailView ']);
|
|
Widget := PGtkWidget(OpenDialog.Handle);
|
|
{$IfDef GTK2}
|
|
FileName := gtk_file_chooser_get_filename(PGtkFileChooser(Widget));
|
|
{$ELSE}
|
|
FileName := gtk_file_selection_get_filename(PGtkFileSelection(Widget));
|
|
{$ENDIF}
|
|
OldFilename := OpenDialog.Filename;
|
|
if Filename = OldFilename then
|
|
Exit;
|
|
OpenDialog.Filename := Filename;
|
|
// tell application, that selection has changed
|
|
OpenDialog.DoSelectionChange;
|
|
if (OpenDialog.OnFolderChange <> nil) and
|
|
(ExtractFilePath(Filename) <> ExtractFilePath(OldFilename)) then
|
|
OpenDialog.DoFolderChange;
|
|
// show some information
|
|
FileDetailLabel := gtk_object_get_data(PGtkObject(OpenDialog.Handle), 'FileDetailLabel');
|
|
if FileDetailLabel = nil then
|
|
Exit;
|
|
if FileExistsUTF8(Filename) then
|
|
Details := GetFileDescription(Filename)
|
|
else
|
|
Details := Format(rsFileInfoFileNotFound, [Filename]);
|
|
gtk_label_set_text(PGtkLabel(FileDetailLabel), PChar(Details));
|
|
end;
|
|
|
|
// ------------------------ Signals --------------------------------------------
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function GTKDialogSelectRowCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever a row is selected in a commondialog
|
|
-------------------------------------------------------------------------------}
|
|
function gtkDialogSelectRowCB(widget: PGtkWidget; Row, Column: gInt;
|
|
bevent: pgdkEventButton; data: gPointer): GBoolean; cdecl;
|
|
var
|
|
theDialog: TCommonDialog;
|
|
MenuWidget: PGtkWidget;
|
|
AFilterEntry: TFileSelFilterEntry;
|
|
FileSelWidget: PGtkFileSelection;
|
|
ShiftState: TShiftState;
|
|
loop : gint;
|
|
startRow : gint;
|
|
endRow : gint;
|
|
begin
|
|
//debugln('GTKDialogSelectRowCB A ');
|
|
Result:=CallBackDefaultReturn;
|
|
if (Data=nil) or (BEvent=nil) or (Column=0) or (Row=0) then ;
|
|
theDialog:=TCommonDialog(GetLCLObject(Widget));
|
|
if (theDialog is TOpenDialog) then begin
|
|
// only process the callback if there is event data. If there isn't any
|
|
// event data that means it was called due to a direct function call of the
|
|
// widget and not an actual mouse click on the widget.
|
|
FileSelWidget:=PGtkFileSelection(theDialog.Handle);
|
|
if (bevent <> nil) and (gdk_event_get_type(bevent) = GDK_2BUTTON_PRESS)
|
|
and (FileSelWidget^.dir_list = widget) then begin
|
|
MenuWidget := gtk_object_get_data(PGtkObject(FileSelWidget),
|
|
'LCLFilterMenu');
|
|
if MenuWidget <> nil then begin
|
|
AFilterEntry := TFileSelFilterEntry(gtk_object_get_data(PGtkObject(
|
|
gtk_menu_get_active(PGtkMenu(MenuWidget))), 'LCLIsFilterMenuItem'));
|
|
if (AFilterEntry<>nil) and (AFilterEntry.Mask<>nil) then
|
|
PopulateFileAndDirectoryLists(FileSelWidget,AFilterEntry.Mask);
|
|
end;
|
|
end
|
|
else if (bevent <> nil)
|
|
and (ofAllowMultiSelect in TOpenDialog(theDialog).Options)
|
|
and (FileSelWidget^.file_list=widget) then begin
|
|
// multi selection
|
|
ShiftState := GTKEventStateToShiftState(BEvent^.State);
|
|
if ssShift in ShiftState then begin
|
|
if LastFileSelectRow <> -1 then begin
|
|
startRow := LastFileSelectRow;
|
|
endRow := row;
|
|
if LastFileSelectRow > row then begin
|
|
startRow := row;
|
|
endRow := LastFileSelectRow;
|
|
end;
|
|
for loop := startRow to endRow do begin
|
|
gtk_clist_select_row(PGtkCList(widget), loop, column);
|
|
end;
|
|
end;
|
|
end
|
|
else if not (ssCtrl in ShiftState) then begin
|
|
gtk_clist_unselect_all(PGtkCList(widget));
|
|
gtk_clist_select_row(PGtkCList(widget), row, column);
|
|
end;
|
|
LastFileSelectRow := row;
|
|
end;
|
|
UpdateDetailView(TOpenDialog(theDialog));
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function gtkDialogHelpclickedCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever the user clicks the help button in a
|
|
commondialog
|
|
-------------------------------------------------------------------------------}
|
|
function gtkDialogHelpclickedCB(widget: PGtkWidget; data: gPointer): GBoolean; cdecl;
|
|
var
|
|
theDialog : TCommonDialog;
|
|
begin
|
|
Result := CallBackDefaultReturn;
|
|
if (Widget=nil) then ;
|
|
theDialog := TCommonDialog(data);
|
|
if theDialog is TOpenDialog then begin
|
|
if TOpenDialog(theDialog).OnHelpClicked<>nil then
|
|
TOpenDialog(theDialog).OnHelpClicked(theDialog);
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function gtkDialogApplyclickedCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever the user clicks the Apply button in a
|
|
commondialog
|
|
-------------------------------------------------------------------------------}
|
|
function gtkDialogApplyclickedCB(widget: PGtkWidget; data: gPointer): GBoolean;
|
|
cdecl;
|
|
var
|
|
theDialog : TCommonDialog;
|
|
FontName: string;
|
|
ALogFont: TLogFont;
|
|
{$ifdef GTK2}
|
|
FontDesc: PPangoFontDescription;
|
|
{$endif}
|
|
begin
|
|
Result := CallBackDefaultReturn;
|
|
if (Widget=nil) then ;
|
|
theDialog := TCommonDialog(data);
|
|
if (theDialog is TFontDialog)
|
|
and (fdApplyButton in TFontDialog(theDialog).Options)
|
|
and (Assigned(TFontDialog(theDialog).OnApplyClicked)) then begin
|
|
FontName := gtk_font_selection_dialog_get_font_name(
|
|
pgtkfontselectiondialog(theDialog.Handle));
|
|
if IsFontNameXLogicalFontDesc(FontName) then begin
|
|
// extract basic font attributes from the font name in XLFD format
|
|
ALogFont:=XLFDNameToLogFont(FontName);
|
|
TFontDialog(theDialog).Font.Assign(ALogFont);
|
|
// set the font name in XLFD format
|
|
// a font name in XLFD format overrides in the gtk interface all other font
|
|
// settings.
|
|
TFontDialog(theDialog).Font.Name := FontName;
|
|
end else begin
|
|
{$ifdef GTK2}
|
|
FontDesc := pango_font_description_from_string(PChar(FontName));
|
|
with TFontDialog(theDialog).Font do
|
|
begin
|
|
BeginUpdate;
|
|
Size := pango_font_description_get_size(FontDesc) div PANGO_SCALE;
|
|
if pango_font_description_get_weight(FontDesc) >= PANGO_WEIGHT_BOLD then
|
|
Style := Style + [fsBold]
|
|
else
|
|
Style := Style - [fsBold];
|
|
if pango_font_description_get_style(FontDesc) > PANGO_STYLE_NORMAL then
|
|
Style := Style + [fsItalic]
|
|
else
|
|
Style := Style - [fsItalic];
|
|
Name := pango_font_description_get_family(FontDesc);
|
|
EndUpdate;
|
|
end;
|
|
pango_font_description_free(FontDesc);
|
|
{$else}
|
|
debugln('Gtk1 should have valid XLogicalFontDesc!');
|
|
{$endif}
|
|
end;
|
|
TFontDialog(theDialog).OnApplyClicked(theDialog);
|
|
end;
|
|
end;
|
|
|
|
function gtkDialogOKclickedCB( widget: PGtkWidget; data: gPointer) : GBoolean; cdecl;
|
|
var
|
|
theDialog : TCommonDialog;
|
|
Fpointer : Pointer;
|
|
// colordialog
|
|
colorsel : PGtkColorSelection;
|
|
newColor : TGdkColor;
|
|
// fontdialog
|
|
FontName : String;
|
|
ALogFont : TLogFont;
|
|
// filedialog
|
|
rowNum : gint;
|
|
fileInfo : PGChar;
|
|
{$IfDef GTK2}
|
|
fileList : PPgchar;
|
|
FontDesc: PPangoFontDescription;
|
|
{$else}
|
|
cListRow : PGList;
|
|
fileList : PGTKCList;
|
|
{$EndIf}
|
|
DirName : string;
|
|
FileName : string;
|
|
Files: TStringList;
|
|
CurFilename: string;
|
|
//SelectedFont: PGdkFont;
|
|
|
|
function CheckOpenedFilename(var AFilename: string): boolean;
|
|
{$IFDEF GTK1}
|
|
var
|
|
MenuWidget: PGtkWidget;
|
|
AFilterEntry: TFileSelFilterEntry;
|
|
{$ENDIF}
|
|
begin
|
|
Result:=true;
|
|
{$IFDEF GTK1}
|
|
// check if entered file are a real directory
|
|
if DirectoryExistsUTF8(AFileName) then
|
|
begin
|
|
// if only interested in directories, then it's done
|
|
if TheDialog is TSelectDirectoryDialog then
|
|
begin
|
|
result := True;
|
|
exit;
|
|
end;
|
|
// if allowed then jump to that directory
|
|
if not (ofNoChangeDir in TOpenDialog(TheDialog).Options) then
|
|
begin
|
|
// change dir
|
|
gtk_file_selection_set_filename(PGtkFileSelection(FPointer),
|
|
PChar(AppendPathDelim(AFileName)));
|
|
|
|
// populate file list
|
|
MenuWidget := gtk_object_get_data(PGtkObject(PGtkFileSelection(FPointer)), 'LCLFilterMenu');
|
|
if (MenuWidget <> nil) then begin
|
|
AFilterEntry := TFileSelFilterEntry(gtk_object_get_data(PGtkObject(gtk_menu_get_active(
|
|
PGtkMenu(MenuWidget))), 'LCLIsFilterMenuItem'));
|
|
if ((AFilterEntry<>nil) and (AFilterEntry.Mask<>nil)) then
|
|
PopulateFileAndDirectoryLists(PGtkFileSelection(FPointer), AFilterEntry.Mask);
|
|
end;
|
|
end;
|
|
// wait for correct input
|
|
result:=False;
|
|
Exit;
|
|
end;
|
|
|
|
// maybe user entered nonexistent dir
|
|
if ((AFileName<>'') and (IsPathDelimiter(AFileName, Length(AFileName)))) then
|
|
begin
|
|
// cant jump to nonexistent dir
|
|
if not (ofNoChangeDir in TOpenDialog(TheDialog).Options) then
|
|
MessageDlg(rsfdDirectoryMustExist, Format(rsfdDirectoryNotExist,[AFileName]),
|
|
mtError, [mbCancel], 0); // GTK2 shows "The folder contents could not be displayed"
|
|
// wait for correct input
|
|
result:=False;
|
|
Exit;
|
|
end;
|
|
|
|
// check if user selected a file while requesting a directory
|
|
if (AFileName<>'') and (TheDialog is TSelectDirectoryDialog) then begin
|
|
if DirectoryExistsUTF8(ExtractFilePath(AFileName)) then begin
|
|
AFileName:=ExtractFilePath(AFileName);
|
|
result:=true;
|
|
exit;
|
|
end;
|
|
end;
|
|
|
|
{$ENDIF}
|
|
// maybe file already exists
|
|
if (ofOverwritePrompt in TOpenDialog(theDialog).Options)
|
|
and FileExistsUTF8(AFilename) then
|
|
begin
|
|
Result := MessageDlg(rsfdOverwriteFile,
|
|
Format(rsfdFileAlreadyExists,[AFileName]),
|
|
mtConfirmation,[mbOk,mbCancel],0)=mrOk;
|
|
if not Result then exit;
|
|
end;
|
|
end;
|
|
|
|
procedure AddFile(List: TStrings; const NewFile: string);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i:=0 to List.Count-1 do
|
|
if List[i]=NewFile then exit;
|
|
List.Add(NewFile);
|
|
end;
|
|
|
|
begin
|
|
Result := True;
|
|
if (Widget=nil) then ;
|
|
theDialog := TCommonDialog(data);
|
|
FPointer := Pointer(theDialog.Handle);
|
|
|
|
if theDialog is TFileDialog then
|
|
begin
|
|
{$IfDef GTK2}
|
|
FileName:=gtk_file_chooser_get_filename(PGtkFileChooser(FPointer));
|
|
{$ELSE}
|
|
FileName:=gtk_file_selection_get_filename(
|
|
PGtkFileSelection(FPointer));
|
|
{$ENDIF}
|
|
if theDialog is TOpenDialog then
|
|
begin
|
|
// check extra options
|
|
if ofAllowMultiSelect in TOpenDialog(theDialog).Options then
|
|
begin
|
|
DirName:=ExtractFilePath(FileName);
|
|
TFileDialog(data).FileName := '';
|
|
Files:=TStringList(TFileDialog(theDialog).Files);
|
|
Files.Clear;
|
|
if (Filename<>'') then begin
|
|
Result:=CheckOpenedFilename(Filename);
|
|
if not Result then exit;
|
|
AddFile(Files,FileName);
|
|
end;
|
|
{$IfDef GTK2}
|
|
fileList := gtk_file_selection_get_selections(PGtkFileSelection(FPointer));
|
|
rowNum := 0;
|
|
While FileList^ <> nil do
|
|
begin
|
|
fileInfo := FileList^;
|
|
CurFilename:=fileInfo; // convert PChar to AnsiString (not typecast)
|
|
if (CurFilename<>'') and (Files.IndexOf(CurFilename)<0) then begin
|
|
CurFilename:=DirName+fileInfo;
|
|
Result:=CheckOpenedFilename(CurFilename);
|
|
if not Result then exit;
|
|
Files.Add(CurFilename);
|
|
end;
|
|
inc(FileList);
|
|
inc(rowNum);
|
|
end;
|
|
Dec(FileList, rowNum);
|
|
g_strfreev(fileList);
|
|
{$Else}
|
|
fileList := PGtkCList(PGtkFileSelection(FPointer)^.file_list);
|
|
rowNum := 0;
|
|
cListRow := fileList^.row_list;
|
|
while cListRow <> nil do
|
|
begin
|
|
if PGtkCListRow(cListRow^.data)^.state = GTK_STATE_SELECTED then
|
|
begin
|
|
if gtk_clist_get_cell_type(fileList, rowNum, 0) = GTK_CELL_TEXT
|
|
then begin
|
|
gtk_clist_get_text(fileList, rowNum, 0, @fileInfo);
|
|
CurFilename:=DirName+fileInfo;
|
|
Result:=CheckOpenedFilename(CurFilename);
|
|
if not Result then exit;
|
|
AddFile(Files,CurFilename);
|
|
end;
|
|
end;
|
|
// get next row from list
|
|
rowNum := rowNum + 1;
|
|
cListRow := g_list_next(cListRow);
|
|
end;
|
|
{$EndIf}
|
|
end else begin
|
|
Result:=CheckOpenedFilename(Filename);
|
|
if not Result then exit;
|
|
TFileDialog(data).FileName := Filename;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
TFileDialog(data).FileName := Filename;
|
|
end;
|
|
end
|
|
else if theDialog is TColorDialog then
|
|
begin
|
|
colorSel := PGtkColorSelection(PGtkColorSelectionDialog(FPointer)^.colorsel);
|
|
gtk_color_selection_get_current_color(colorsel, @newColor);
|
|
TColorDialog(theDialog).Color := TGDKColorToTColor(newcolor);
|
|
{$IFDEF VerboseColorDialog}
|
|
DebugLn('gtkDialogOKclickedCB ',DbgS(TColorDialog(theDialog).Color));
|
|
{$ENDIF}
|
|
end
|
|
else if theDialog is TFontDialog then
|
|
begin
|
|
Assert(False, 'Trace:Pressed OK in FontDialog');
|
|
FontName := gtk_font_selection_dialog_get_font_name(
|
|
pgtkfontselectiondialog(FPointer));
|
|
//debugln('gtkDialogOKclickedCB FontName=',FontName);
|
|
//SelectedFont:=gdk_font_load(PChar(FontName));
|
|
//debugln('gtkDialogOKclickedCB ',dbgs(SelectedFont));
|
|
|
|
if IsFontNameXLogicalFontDesc(FontName) then begin
|
|
// extract basic font attributes from the font name in XLFD format
|
|
ALogFont:=XLFDNameToLogFont(FontName);
|
|
TFontDialog(theDialog).Font.Assign(ALogFont);
|
|
// set the font name in XLFD format
|
|
// a font name in XLFD format overrides in the gtk interface all other font
|
|
// settings.
|
|
TFontDialog(theDialog).Font.Name := FontName;
|
|
end else begin
|
|
{$ifdef GTK2}
|
|
FontDesc := pango_font_description_from_string(PChar(FontName));
|
|
with TFontDialog(theDialog).Font do
|
|
begin
|
|
BeginUpdate;
|
|
Size := pango_font_description_get_size(FontDesc) div PANGO_SCALE;
|
|
if pango_font_description_get_weight(FontDesc) >= PANGO_WEIGHT_BOLD then
|
|
Style := Style + [fsBold]
|
|
else
|
|
Style := Style - [fsBold];
|
|
if pango_font_description_get_style(FontDesc) > PANGO_STYLE_NORMAL then
|
|
Style := Style + [fsItalic]
|
|
else
|
|
Style := Style - [fsItalic];
|
|
Name := pango_font_description_get_family(FontDesc);
|
|
EndUpdate;
|
|
end;
|
|
pango_font_description_free(FontDesc);
|
|
{$else}
|
|
debugln('Gtk1 should have valid XLogicalFontDesc!');
|
|
{$endif}
|
|
end;
|
|
|
|
Assert(False, 'Trace:-----'+TFontDialog(theDialog).Font.Name+'----');
|
|
end;
|
|
|
|
StoreCommonDialogSetup(theDialog);
|
|
theDialog.UserChoice := mrOK;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function gtkDialogCancelclickedCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever the user clicks the cancel button in a
|
|
commondialog
|
|
-------------------------------------------------------------------------------}
|
|
function gtkDialogCancelclickedCB(widget: PGtkWidget; data: gPointer): GBoolean;
|
|
cdecl;
|
|
var
|
|
theDialog : TCommonDialog;
|
|
begin
|
|
Result := CallBackDefaultReturn;
|
|
if (Widget=nil) then ;
|
|
theDialog := TCommonDialog(data);
|
|
if theDialog is TFileDialog then
|
|
begin
|
|
TFileDialog(data).FileName := '';
|
|
end;
|
|
StoreCommonDialogSetup(theDialog);
|
|
theDialog.UserChoice := mrCancel;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function GTKDialogRealizeCB
|
|
Params: Widget: PGtkWidget; Data: Pointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever a commondialog window is realized
|
|
-------------------------------------------------------------------------------}
|
|
function GTKDialogRealizeCB(Widget: PGtkWidget; Data: Pointer): GBoolean; cdecl;
|
|
var
|
|
LCLComponent: TObject;
|
|
begin
|
|
if (Data=nil) then ;
|
|
gdk_window_set_events(GetControlWindow(Widget),
|
|
gdk_window_get_events(GetControlWindow(Widget))
|
|
or GDK_KEY_RELEASE_MASK or GDK_KEY_PRESS_MASK);
|
|
LCLComponent:=GetLCLObject(Widget);
|
|
if LCLComponent is TCommonDialog then
|
|
TCommonDialog(LCLComponent).DoShow;
|
|
Result:=true;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function gtkDialogCloseQueryCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, before a commondialog is destroyed
|
|
-------------------------------------------------------------------------------}
|
|
function gtkDialogCloseQueryCB(widget: PGtkWidget; data: gPointer): GBoolean;
|
|
cdecl;
|
|
var
|
|
theDialog : TCommonDialog;
|
|
CanClose: boolean;
|
|
begin
|
|
Result := False; // true = do nothing, false = destroy or hide window
|
|
if (Data=nil) then ;
|
|
// data is not the commondialog. Get it manually.
|
|
theDialog := TCommonDialog(GetLCLObject(Widget));
|
|
if theDialog=nil then exit;
|
|
if theDialog.OnCanClose<>nil then begin
|
|
CanClose:=True;
|
|
theDialog.OnCanClose(theDialog,CanClose);
|
|
Result:=not CanClose;
|
|
end;
|
|
if not Result then begin
|
|
StoreCommonDialogSetup(theDialog);
|
|
DestroyCommonDialogAddOns(theDialog);
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function gtkDialogDestroyCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, when a commondialog is destroyed
|
|
-------------------------------------------------------------------------------}
|
|
function gtkDialogDestroyCB(widget: PGtkWidget; data: gPointer): GBoolean; cdecl;
|
|
begin
|
|
Result := True;
|
|
if (Widget=nil) then ;
|
|
TCommonDialog(data).UserChoice := mrAbort;
|
|
TCommonDialog(data).Close;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function GTKDialogKeyUpDownCB
|
|
Params: Widget: PGtkWidget; Event : pgdkeventkey; Data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever a key is pressed or released in a common
|
|
dialog window
|
|
-------------------------------------------------------------------------------}
|
|
function GTKDialogKeyUpDownCB(Widget: PGtkWidget; Event : pgdkeventkey;
|
|
Data: gPointer) : GBoolean; cdecl;
|
|
begin
|
|
//debugln('GTKDialogKeyUpDownCB A ');
|
|
Result:=CallBackDefaultReturn;
|
|
|
|
if (Widget=nil) then ;
|
|
case gdk_event_get_type(Event) of
|
|
|
|
GDK_KEY_RELEASE, GDK_KEY_PRESS:
|
|
begin
|
|
if Event^.KeyVal = GDK_KEY_Escape
|
|
then begin
|
|
StoreCommonDialogSetup(TCommonDialog(data));
|
|
TCommonDialog(data).UserChoice:=mrCancel;
|
|
end;
|
|
if (TCommonDialog(data) is TOpenDialog) then begin
|
|
UpdateDetailView(TOpenDialog(data));
|
|
end;
|
|
end;
|
|
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function GTKDialogFocusInCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, when a widget of a commondialog gets focus
|
|
-------------------------------------------------------------------------------}
|
|
function GTKDialogFocusInCB(widget: PGtkWidget; data: gPointer): GBoolean;
|
|
cdecl;
|
|
var
|
|
theDialog: TCommonDialog;
|
|
begin
|
|
//debugln('GTKDialogFocusInCB A ');
|
|
Result:=CallBackDefaultReturn;
|
|
if (Data=nil) then ;
|
|
theDialog:=TCommonDialog(GetLCLObject(Widget));
|
|
if (theDialog is TOpenDialog) then begin
|
|
UpdateDetailView(TOpenDialog(theDialog));
|
|
end;
|
|
end;
|
|
|
|
{-------------------------------------------------------------------------------
|
|
function GTKDialogMenuActivateCB
|
|
Params: widget: PGtkWidget; data: gPointer
|
|
Result: GBoolean
|
|
|
|
This function is called, whenever a menu of a commondialog is activated
|
|
-------------------------------------------------------------------------------}
|
|
function GTKDialogMenuActivateCB(widget: PGtkWidget; data: gPointer): GBoolean;
|
|
cdecl;
|
|
var
|
|
theDialog: TCommonDialog;
|
|
|
|
procedure CheckFilterActivated(FilterWidget: PGtkWidget);
|
|
var
|
|
AFilterEntry: TFileSelFilterEntry;
|
|
begin
|
|
if FilterWidget=nil then exit;
|
|
AFilterEntry:=TFileSelFilterEntry(gtk_object_get_data(PGtkObject(FilterWidget),
|
|
'LCLIsFilterMenuItem'));
|
|
if (AFilterEntry<>nil) and (AFilterEntry.Mask<>nil) then
|
|
begin
|
|
PopulateFileAndDirectoryLists(PGtkFileSelection(theDialog.Handle),
|
|
AFilterEntry.Mask);
|
|
TFileDialog(TheDialog).IntfFileTypeChanged(AFilterEntry.FilterIndex + 1);
|
|
UpdateDetailView(TOpenDialog(theDialog));
|
|
end;
|
|
end;
|
|
|
|
var
|
|
AHistoryEntry: PFileSelHistoryEntry;
|
|
{$IFDEF Gtk1}
|
|
FilterMenu, ActiveFilterMenuItem: PGtkWidget;
|
|
{$ENDIF}
|
|
begin
|
|
Result:=false;
|
|
if (Data=nil) then ;
|
|
theDialog:=TCommonDialog(GetNearestLCLObject(Widget));
|
|
if (theDialog is TOpenDialog) then begin
|
|
// check if history activated
|
|
AHistoryEntry:=gtk_object_get_data(PGtkObject(Widget),
|
|
'LCLIsHistoryMenuItem');
|
|
if (AHistoryEntry<>nil) and (AHistoryEntry^.Filename<>nil) then begin
|
|
// user has choosen a history file
|
|
// -> select it in the filedialog
|
|
{$IFDEF GTK1}
|
|
gtk_file_selection_complete(PGtkFileSelection(theDialog.Handle),
|
|
AHistoryEntry^.Filename);
|
|
// restore filter
|
|
if DirPathExists(AHistoryEntry^.Filename) then begin
|
|
FilterMenu:=gtk_object_get_data(PGtkObject(theDialog.Handle),
|
|
'LCLFilterMenu');
|
|
if FilterMenu<>nil then begin
|
|
ActiveFilterMenuItem:=gtk_menu_get_active(GTK_MENU(FilterMenu));
|
|
CheckFilterActivated(ActiveFilterMenuItem);
|
|
end;
|
|
end;
|
|
{$ELSE}
|
|
gtk_file_chooser_set_current_folder(PGtkFileChooser(theDialog.Handle),AHistoryEntry^.Filename);
|
|
{$ENDIF}
|
|
UpdateDetailView(TOpenDialog(theDialog));
|
|
end;
|
|
{$IFDEF GTK1}
|
|
// check if filter activated
|
|
CheckFilterActivated(Widget);
|
|
{$ENDIF}
|
|
end;
|
|
end;
|
|
|
|
// -------------------- END OF Signals -----------------------------------------
|
|
|
|
{------------------------------------------------------------------------------
|
|
Method: SetColorDialogColor
|
|
Params: ColorSelection : a gtk color selection dialog;
|
|
Color : the color to select
|
|
Returns: nothing
|
|
|
|
Set the color of the color selection dialog
|
|
------------------------------------------------------------------------------}
|
|
procedure SetColorDialogColor(ColorSelection: PGtkColorSelection;
|
|
Color: TColor);
|
|
var
|
|
SelectionColor: TGDKColor;
|
|
colorSel : PGTKCOLORSELECTION;
|
|
begin
|
|
{$IFDEF VerboseColorDialog}
|
|
DebugLn('TGtkWidgetSet.SetColorDialogColor Start Color=',DbgS(Color));
|
|
{$ENDIF}
|
|
Color:=ColorToRGB(Color);
|
|
{$IFDEF VerboseColorDialog}
|
|
DebugLn('TGtkWidgetSet.SetColorDialogColor Converted Color=',DbgS(Color));
|
|
{$ENDIF}
|
|
SelectionColor.Pixel := 0;
|
|
SelectionColor.Red := Red(Color) shl 8;
|
|
SelectionColor.Green:= Green(Color) shl 8;
|
|
SelectionColor.Blue:= Blue(Color) shl 8;
|
|
colorSel := PGTKCOLORSELECTION((PGTKCOLORSELECTIONDIALOG(ColorSelection))^.colorsel);
|
|
gtk_color_selection_set_current_color(colorSel,@SelectionColor);
|
|
end;
|
|
|
|
class procedure TGtkWSCommonDialog.ShowModal(const ACommonDialog: TCommonDialog);
|
|
var
|
|
GtkWindow: PGtkWindow;
|
|
{$IFDEF Gtk1}
|
|
{$IFDEF UseXinerama}
|
|
Requisition: TGtkRequisition;
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
begin
|
|
ReleaseMouseCapture;
|
|
GtkWindow:=PGtkWindow(ACommonDialog.Handle);
|
|
gtk_window_set_title(GtkWindow,PChar(ACommonDialog.Title));
|
|
if ACommonDialog is TColorDialog then
|
|
SetColorDialogColor(PGtkColorSelection(GtkWindow),
|
|
TColorDialog(ACommonDialog).Color);
|
|
{$IFDEF Gtk1}
|
|
{$IFDEF UseXinerama}
|
|
if GetFirstScreen then begin
|
|
{ Fix multi screen problems, at least partially by forcing dialog to centre of first screen }
|
|
gtk_widget_size_request(PGtkWidget(GtkWindow), @Requisition);
|
|
gtk_widget_set_uposition(PGtkWidget(GtkWindow), (FirstScreen.x - Requisition.width) div 2,
|
|
(FirstScreen.y - Requisition.height) div 2);
|
|
end else
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
gtk_window_set_position(GtkWindow, GTK_WIN_POS_CENTER);
|
|
GtkWindowShowModal(GtkWindow);
|
|
end;
|
|
|
|
class procedure TGtkWSCommonDialog.SetCallbacks(const AGtkWidget: PGtkWidget;
|
|
const AWidgetInfo: PWidgetInfo);
|
|
begin
|
|
g_signal_connect(PGtkObject(AGtkWidget),
|
|
'destroy', gtk_Signal_Func(@gtkDialogDestroyCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(PGtkObject(AGtkWidget),
|
|
'delete-event', gtk_Signal_Func(@gtkDialogCloseQueryCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(PGtkObject(AGtkWidget),
|
|
'key-press-event', gtk_Signal_Func(@GTKDialogKeyUpDownCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(PGtkObject(AGtkWidget),
|
|
'key-release-event', gtk_Signal_Func(@GTKDialogKeyUpDownCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(PGtkObject(AGtkWidget),
|
|
'realize', gtk_Signal_Func(@GTKDialogRealizeCB), AWidgetInfo^.LCLObject);
|
|
end;
|
|
|
|
class procedure TGtkWSCommonDialog.SetSizes(const AGtkWidget: PGtkWidget;
|
|
const AWidgetInfo: PWidgetInfo);
|
|
var
|
|
NewWidth, NewHeight: integer;
|
|
begin
|
|
// set default size
|
|
NewWidth := TCommonDialog(AWidgetInfo^.LCLObject).Width;
|
|
if NewWidth <= 0 then
|
|
NewWidth := -2; // -2 = let the window manager decide
|
|
NewHeight := TCommonDialog(AWidgetInfo^.LCLObject).Height;
|
|
if NewHeight<=0 then
|
|
NewHeight := -2; // -2 = let the window manager decide
|
|
if (NewWidth > 0) or (NewHeight > 0) then
|
|
gtk_window_set_default_size(PGtkWindow(AGtkWidget), NewWidth, NewHeight);
|
|
end;
|
|
|
|
class function TGtkWSCommonDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
|
|
begin
|
|
Result := 0;
|
|
DebugLn('TGtkWSCommonDialog.CreateHandle is generic dialog handle constructor => implement CreateHandle for: ', dbgsName(ACommonDialog))
|
|
end;
|
|
|
|
class procedure TGtkWSCommonDialog.DestroyHandle(const ACommonDialog: TCommonDialog);
|
|
begin
|
|
{ TODO: cleanup }
|
|
TGtkWidgetSet(WidgetSet).DestroyLCLComponent(ACommonDialog);
|
|
end;
|
|
|
|
{ TGtkWSColorDialog }
|
|
|
|
class procedure TGtkWSColorDialog.SetCallbacks(const AGtkWidget: PGtkWidget;
|
|
const AWidgetInfo: PWidgetInfo);
|
|
begin
|
|
TGtkWSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo);
|
|
g_signal_connect(PGtkObject(PGtkColorSelectionDialog(AGtkWidget)^.ok_button),
|
|
'clicked', gtk_signal_func(@gtkDialogOKclickedCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(PGtkObject(PGtkColorSelectionDialog(AGtkWidget)^.cancel_button),
|
|
'clicked', gtk_signal_func(@gtkDialogCancelclickedCB), AWidgetInfo^.LCLObject);
|
|
end;
|
|
|
|
class function TGtkWSColorDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
|
|
var
|
|
Widget: PGtkWidget;
|
|
WidgetInfo: PWidgetInfo;
|
|
begin
|
|
Widget := gtk_color_selection_dialog_new(PChar(ACommonDialog.Title));
|
|
Result := THandle(PtrUInt(Widget));
|
|
WidgetInfo := CreateWidgetInfo(Widget);
|
|
WidgetInfo^.LCLObject := ACommonDialog;
|
|
TGtkWSCommonDialog.SetSizes(Widget, WidgetInfo);
|
|
SetCallbacks(Widget, WidgetInfo);
|
|
end;
|
|
|
|
{ TGtkWSFileDialog }
|
|
|
|
class procedure TGtkWSFileDialog.SetCallbacks(const AGtkWidget: PGtkWidget;
|
|
const AWidgetInfo: PWidgetInfo);
|
|
begin
|
|
TGtkWSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo);
|
|
{****This is a major hack put by Cliff Baeseman to solve
|
|
a gtk win32 dll implementation problem where the headers implementation
|
|
does not match the linux version**** }
|
|
{$IFNDEF WIN32}
|
|
g_signal_connect(gtk_object(PGtkFileSelection(AGtkWidget)^.ok_button),
|
|
'clicked', gtk_signal_func(@gtkDialogOKclickedCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(gtk_object(PGtkFileSelection(AGtkWidget)^.cancel_button),
|
|
'clicked', gtk_signal_func(@gtkDialogCancelclickedCB), AWidgetInfo^.LCLObject);
|
|
{$ELSE}
|
|
g_signal_connect(gtk_object(PGtkFileSelection(AGtkWidget)^.cancel_button),
|
|
'clicked', gtk_signal_func(@gtkDialogOKclickedCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(gtk_object(PGtkFileSelection(AGtkWidget)^.help_button),
|
|
'clicked', gtk_signal_func(@gtkDialogCancelclickedCB), AWidgetInfo^.LCLObject);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
class function TGtkWSFileDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
|
|
var
|
|
Widget: PGtkWidget;
|
|
WidgetInfo: PWidgetInfo;
|
|
begin
|
|
// for: csFileDialog, csOpenFileDialog, csSaveFileDialog, csSelectDirectoryDialog, csPreviewFileDialog
|
|
Widget := gtk_file_selection_new(PChar(ACommonDialog.Title));
|
|
|
|
Result := THandle(PtrUInt(Widget));
|
|
WidgetInfo := CreateWidgetInfo(Widget);
|
|
WidgetInfo^.LCLObject := ACommonDialog;
|
|
TGtkWSCommonDialog.SetSizes(Widget, WidgetInfo);
|
|
SetCallbacks(Widget, WidgetInfo);
|
|
end;
|
|
|
|
{ TGtkWSOpenDialog }
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: TGtkWidgetSet.CreateOpenDialogFilter
|
|
Params: OpenDialog: TOpenDialog; SelWidget: PGtkWidget
|
|
Returns: -
|
|
|
|
Adds a Filter pulldown to a gtk file selection dialog. Returns the
|
|
inital filter mask.
|
|
------------------------------------------------------------------------------}
|
|
class function TGtkWSOpenDialog.CreateOpenDialogFilter(OpenDialog: TOpenDialog;
|
|
SelWidget: PGtkWidget): string;
|
|
var
|
|
FilterList: TFPList;
|
|
HBox, LabelWidget, FilterPullDownWidget,
|
|
MenuWidget, MenuItemWidget: PGtkWidget;
|
|
i, j, CurMask: integer;
|
|
s: String;
|
|
begin
|
|
ExtractFilterList(OpenDialog.Filter,FilterList,false);
|
|
if FilterList.Count>0 then begin
|
|
|
|
// create a HBox so that the filter pulldown is left justified
|
|
HBox:=gtk_hbox_new(false,0);
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLFilterHBox', HBox);
|
|
gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(SelWidget)^.main_vbox),
|
|
HBox,false,false,0);
|
|
|
|
// create the label 'Filter:'
|
|
s:=rsgtkFilter;
|
|
LabelWidget:=gtk_label_new(PChar(s));
|
|
gtk_box_pack_start(GTK_BOX(HBox),LabelWidget,false,false,5);
|
|
gtk_widget_show(LabelWidget);
|
|
|
|
// create the pull down
|
|
FilterPullDownWidget:=gtk_option_menu_new;
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLFilterPullDown',
|
|
FilterPullDownWidget);
|
|
gtk_box_pack_start(GTK_BOX(HBox),FilterPullDownWidget,false,false,5);
|
|
gtk_widget_show(FilterPullDownWidget);
|
|
gtk_widget_show(HBox);
|
|
|
|
// create the menu (the content of the pull down)
|
|
MenuWidget:=gtk_menu_new;
|
|
SetLCLObject(MenuWidget,OpenDialog);
|
|
for i:=0 to FilterList.Count-1 do begin
|
|
// create the menu items in the filter menu
|
|
MenuItemWidget:=gtk_menu_item_new_with_label(
|
|
TFileSelFilterEntry(FilterList[i]).Description);
|
|
// connect the new MenuItem to the FilterList entry
|
|
gtk_object_set_data(PGtkObject(MenuItemWidget), 'LCLIsFilterMenuItem',
|
|
FilterList[i]);
|
|
// add activation signal and add to menu
|
|
g_signal_connect(GTK_OBJECT(MenuItemWidget), 'activate',
|
|
gtk_signal_func(@GTKDialogMenuActivateCB),
|
|
OpenDialog);
|
|
gtk_menu_append(MenuWidget, MenuItemWidget);
|
|
gtk_widget_show(MenuItemWidget);
|
|
end;
|
|
gtk_widget_show(MenuWidget);
|
|
gtk_option_menu_set_menu(GTK_OPTION_MENU(FilterPullDownWidget),
|
|
MenuWidget);
|
|
end else begin
|
|
MenuWidget:=nil;
|
|
end;
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLFilterMenu', MenuWidget);
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLFilterList', FilterList);
|
|
|
|
// set the initial filter
|
|
Result := 'none'; { Don't use '' as null return as this is used for *.* }
|
|
if FilterList.Count>0 then begin
|
|
i:=0;
|
|
j:=OpenDialog.FilterIndex - 1; // FilterIndex is 1 based
|
|
if j<0 then j:=0;
|
|
CurMask:=0;
|
|
while (i<FilterList.Count) do begin
|
|
if TFileSelFilterEntry(FilterList[i]).FilterIndex=j
|
|
then begin
|
|
CurMask:=i;
|
|
break;
|
|
end;
|
|
inc(i);
|
|
end;
|
|
Result := TFileSelFilterEntry(FilterList[CurMask]).Mask;
|
|
gtk_option_menu_set_history(GTK_OPTION_MENU(FilterPullDownWidget), CurMask);
|
|
end;
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: TGtkWSOpenDialog.CreatePreviewDialogControl
|
|
Params: PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget
|
|
Returns: -
|
|
|
|
Adds a preview control to a gtk file selection dialog.
|
|
------------------------------------------------------------------------------}
|
|
class procedure TGtkWSOpenDialog.CreatePreviewDialogControl(
|
|
PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget);
|
|
var
|
|
PreviewWidget: PGtkWidget;
|
|
list_hbox: PGtkWidget;
|
|
DirListWidget: PGtkWidget;
|
|
ScrolledWin: PGtkWidget;
|
|
AControl: TPreviewFileControl;
|
|
begin
|
|
AControl:=PreviewDialog.PreviewFileControl;
|
|
if AControl=nil then exit;
|
|
// find the hbox widget of the file and directory dialog
|
|
DirListWidget:=PGtkFileSelection(SelWidget)^.dir_list;
|
|
ScrolledWin:=DirListWidget^.parent;
|
|
if not GtkWidgetIsA(ScrolledWin, GTK_TYPE_SCROLLED_WINDOW) then
|
|
begin
|
|
DebugLn('NOTE: CreatePreviewDialogControl ',
|
|
'parent widget of dir_list widget is not a scrolled window');
|
|
exit;
|
|
end;
|
|
list_hbox:=ScrolledWin^.parent;
|
|
if not GtkWidgetIsA(list_hbox,GTK_TYPE_HBOX) then begin
|
|
DebugLn('NOTE: CreatePreviewDialogControl ',
|
|
'parent widget of scrolled window is not a hbox');
|
|
exit;
|
|
end;
|
|
// create the preview widget
|
|
PreviewWidget:=PGtkWidget(AControl.Handle);
|
|
gtk_object_set_data(PGtkObject(PreviewWidget),'LCLPreviewFixed',
|
|
PreviewWidget);
|
|
gtk_widget_set_usize(PreviewWidget,AControl.Width,AControl.Height);
|
|
gtk_box_pack_start(GTK_BOX(list_hbox),PreviewWidget,true,true,0);
|
|
gtk_widget_show(PreviewWidget);
|
|
end;
|
|
|
|
{------------------------------------------------------------------------------
|
|
Function: CreateOpenDialogHistory
|
|
Params: OpenDialog: TOpenDialog; SelWidget: PGtkWidget
|
|
Returns: -
|
|
|
|
Adds a History pulldown to a gtk file selection dialog.
|
|
------------------------------------------------------------------------------}
|
|
class procedure TGtkWSOpenDialog.CreateOpenDialogHistory(OpenDialog: TOpenDialog; SelWidget: PGtkWidget);
|
|
var
|
|
HistoryList: TFPList; // list of THistoryListEntry
|
|
AHistoryEntry: PFileSelHistoryEntry;
|
|
i: integer;
|
|
s: string;
|
|
HBox, LabelWidget, HistoryPullDownWidget,
|
|
MenuWidget, MenuItemWidget: PGtkWidget;
|
|
begin
|
|
if OpenDialog.HistoryList.Count>0 then begin
|
|
|
|
// create the HistoryList where the current state of the history is stored
|
|
HistoryList:=TFPList.Create;
|
|
for i:=0 to OpenDialog.HistoryList.Count-1 do begin
|
|
s:=OpenDialog.HistoryList[i];
|
|
if s<>'' then begin
|
|
New(AHistoryEntry);
|
|
HistoryList.Add(AHistoryEntry);
|
|
AHistoryEntry^.Filename := StrAlloc(length(s)+1);
|
|
StrPCopy(AHistoryEntry^.Filename, s);
|
|
AHistoryEntry^.MenuItem:=nil;
|
|
end;
|
|
end;
|
|
|
|
// create a HBox so that the history is left justified
|
|
HBox:=gtk_hbox_new(false,0);
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLHistoryHBox', HBox);
|
|
{$IFDEF GTK1}
|
|
gtk_box_pack_start(GTK_BOX(GTK_FILE_SELECTION(SelWidget)^.main_vbox),
|
|
HBox,false,false,0);
|
|
{$ELSE}
|
|
gtk_file_chooser_set_extra_widget(PGtkDialog(SelWidget),HBox);
|
|
{$ENDIF}
|
|
|
|
// create the label 'History:'
|
|
s:=rsgtkHistory;
|
|
LabelWidget:=gtk_label_new(PChar(s));
|
|
gtk_box_pack_start(GTK_BOX(HBox),LabelWidget,false,false,5);
|
|
gtk_widget_show(LabelWidget);
|
|
|
|
// create the pull down
|
|
HistoryPullDownWidget:=gtk_option_menu_new;
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLHistoryPullDown',
|
|
HistoryPullDownWidget);
|
|
gtk_box_pack_start(GTK_BOX(HBox),HistoryPullDownWidget,false,false,5);
|
|
gtk_widget_show(HistoryPullDownWidget);
|
|
gtk_widget_show_all(HBox);
|
|
|
|
// create the menu (the content of the pull down)
|
|
MenuWidget:=gtk_menu_new;
|
|
SetLCLObject(MenuWidget,OpenDialog);
|
|
for i:=0 to HistoryList.Count-1 do begin
|
|
// create the menu items in the history menu
|
|
MenuItemWidget:=gtk_menu_item_new_with_label(
|
|
PFileSelHistoryEntry(HistoryList[i])^.Filename);
|
|
// connect the new MenuItem to the HistoryList entry
|
|
gtk_object_set_data(PGtkObject(MenuItemWidget), 'LCLIsHistoryMenuItem',
|
|
HistoryList[i]);
|
|
// add activation signal and add to menu
|
|
g_signal_connect(GTK_OBJECT(MenuItemWidget), 'activate',
|
|
gtk_signal_func(@GTKDialogMenuActivateCB),
|
|
OpenDialog);
|
|
gtk_menu_append(MenuWidget, MenuItemWidget);
|
|
gtk_widget_show(MenuItemWidget);
|
|
end;
|
|
gtk_widget_show(MenuWidget);
|
|
gtk_option_menu_set_menu(GTK_OPTION_MENU(HistoryPullDownWidget),
|
|
MenuWidget);
|
|
end else begin
|
|
MenuWidget:=nil;
|
|
HistoryList:=nil
|
|
end;
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLHistoryMenu', MenuWidget);
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'LCLHistoryList', HistoryList);
|
|
end;
|
|
|
|
class function TGtkWSOpenDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
|
|
var
|
|
SelWidget: PGtkWidget;
|
|
OpenDialog: TOpenDialog absolute ACommonDialog;
|
|
|
|
FileDetailLabel, HBox, FrameWidget: PGtkWidget;
|
|
FileSelWidget: PGtkFileSelection;
|
|
InitialFilter: string;
|
|
begin
|
|
Result := TGtkWSFileDialog.CreateHandle(ACommonDialog);
|
|
SelWidget := PGtkWidget(Result);
|
|
|
|
//DebugLn(['TGtkWidgetSet.InitializeOpenDialog ']);
|
|
FileSelWidget := GTK_FILE_SELECTION(SelWidget);
|
|
|
|
// Help button
|
|
if (ofShowHelp in OpenDialog.Options)
|
|
and (FileSelWidget^.Help_Button<>nil) then begin
|
|
gtk_widget_show(FileSelWidget^.Help_Button);
|
|
g_signal_connect( gtk_object(FileSelWidget^.help_button),
|
|
'clicked', gtk_signal_func(@gtkDialogHelpclickedCB), OpenDialog);
|
|
end;
|
|
|
|
// connect selection entry (edit field for filename)
|
|
if (FileSelWidget^.selection_entry<>nil) then begin
|
|
SetLCLObject(FileSelWidget^.selection_entry,OpenDialog);
|
|
g_signal_connect(
|
|
gtk_object(FileSelWidget^.selection_entry),
|
|
'key-press-event', gtk_signal_func(@GTKDialogKeyUpDownCB),
|
|
OpenDialog);
|
|
g_signal_connect(
|
|
gtk_object(FileSelWidget^.selection_entry),
|
|
'focus-in-event', gtk_signal_func(@GTKDialogFocusInCB), OpenDialog);
|
|
end;
|
|
|
|
// connect dir list (list of directories)
|
|
if (FileSelWidget^.dir_list<>nil) then begin
|
|
SetLCLObject(FileSelWidget^.dir_list,OpenDialog);
|
|
g_signal_connect(gtk_object(FileSelWidget^.dir_list),
|
|
'select-row', gtk_signal_func(@GTKDialogSelectRowCB), OpenDialog);
|
|
end;
|
|
|
|
// connect file list (list of files in current directory)
|
|
if (FileSelWidget^.file_list<>nil) then begin
|
|
LastFileSelectRow := -1;
|
|
SetLCLObject(FileSelWidget^.file_list,OpenDialog);
|
|
g_signal_connect(gtk_object(FileSelWidget^.file_list),
|
|
'select-row', gtk_signal_func(@GTKDialogSelectRowCB), OpenDialog);
|
|
if ofAllowMultiSelect in OpenDialog.Options then
|
|
gtk_clist_set_selection_mode(
|
|
PGtkCList(FileSelWidget^.file_list),GTK_SELECTION_MULTIPLE);
|
|
end;
|
|
|
|
// History List - a frame with an option menu
|
|
CreateOpenDialogHistory(OpenDialog, SelWidget);
|
|
|
|
// Filter - a frame with an option menu
|
|
InitialFilter := CreateOpenDialogFilter(OpenDialog,SelWidget);
|
|
|
|
// Details - a frame with a label
|
|
if (ofViewDetail in OpenDialog.Options) then begin
|
|
// create the frame around the information
|
|
FrameWidget:=gtk_frame_new(PChar(rsFileInformation));
|
|
gtk_box_pack_start(GTK_BOX(FileSelWidget^.main_vbox),
|
|
FrameWidget,false,false,0);
|
|
gtk_widget_show(FrameWidget);
|
|
// create a HBox, so that the information is left justified
|
|
HBox:=gtk_hbox_new(false,0);
|
|
gtk_container_add(GTK_CONTAINER(FrameWidget), HBox);
|
|
// create the label for the file information
|
|
FileDetailLabel:=gtk_label_new(PChar(rsDefaultFileInfoValue));
|
|
gtk_box_pack_start(GTK_BOX(HBox),FileDetailLabel,false,false,5);
|
|
gtk_widget_show_all(HBox);
|
|
end else
|
|
FileDetailLabel:=nil;
|
|
gtk_object_set_data(PGtkObject(SelWidget), 'FileDetailLabel',
|
|
FileDetailLabel);
|
|
|
|
// preview
|
|
if (OpenDialog is TPreviewFileDialog) then
|
|
CreatePreviewDialogControl(TPreviewFileDialog(OpenDialog),SelWidget);
|
|
|
|
// set initial filename
|
|
if OpenDialog.Filename<>'' then
|
|
gtk_file_selection_set_filename(FileSelWidget,PChar(OpenDialog.Filename));
|
|
|
|
if InitialFilter <> 'none' then
|
|
PopulateFileAndDirectoryLists(FileSelWidget, InitialFilter);
|
|
end;
|
|
|
|
{ TGtkWSFontDialog }
|
|
|
|
class procedure TGtkWSFontDialog.SetCallbacks(const AGtkWidget: PGtkWidget;
|
|
const AWidgetInfo: PWidgetInfo);
|
|
begin
|
|
TGtkWSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo);
|
|
// connect Ok, Cancel and Apply Button
|
|
g_signal_connect(
|
|
PGtkObject(PGtkFontSelectionDialog(AGtkWidget)^.ok_button),
|
|
'clicked', gtk_signal_func(@gtkDialogOKclickedCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(
|
|
PGtkObject(PGtkFontSelectionDialog(AGtkWidget)^.cancel_button),
|
|
'clicked', gtk_signal_func(@gtkDialogCancelclickedCB), AWidgetInfo^.LCLObject);
|
|
g_signal_connect(
|
|
PGtkObject(PGtkFontSelectionDialog(AGtkWidget)^.apply_button),
|
|
'clicked', gtk_signal_func(@gtkDialogApplyclickedCB), AWidgetInfo^.LCLObject);
|
|
end;
|
|
|
|
class function TGtkWSFontDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
|
|
{$IFDEF GTK1}
|
|
const
|
|
FixedFilter: array [0..2] of PChar = ( 'c', 'm', nil );
|
|
{$ENDIF}
|
|
|
|
var
|
|
{$IFDEF GTK1}
|
|
SpacingFilter: PPgchar;
|
|
FontType: TGtkFontType;
|
|
{$ELSE}
|
|
FontDesc: PPangoFontDescription;
|
|
TmpStr: pChar;
|
|
{$ENDIF}
|
|
Widget: PGtkWidget;
|
|
WidgetInfo: PWidgetInfo;
|
|
FontDialog: TFontDialog absolute ACommonDialog;
|
|
begin
|
|
Widget := gtk_font_selection_dialog_new(PChar(ACommonDialog.Title));
|
|
|
|
if fdApplyButton in FontDialog.Options then
|
|
gtk_widget_show(PGtkFontSelectionDialog(Widget)^.apply_button);
|
|
// set preview text
|
|
if FontDialog.PreviewText <> '' then
|
|
gtk_font_selection_dialog_set_preview_text(PGtkFontSelectionDialog(Widget),
|
|
PChar(FontDialog.PreviewText));
|
|
|
|
// set font name in XLFD format
|
|
if IsFontNameXLogicalFontDesc(FontDialog.Font.Name) then
|
|
gtk_font_selection_dialog_set_font_name(PGtkFontSelectionDialog(Widget),
|
|
PChar(FontDialog.Font.Name))
|
|
else
|
|
begin
|
|
{$IFDEF GTK1}
|
|
DebugLn('Gtk1 should have IsFontNameXLogicalFontDesc true!');
|
|
{$ELSE}
|
|
FontDesc := pango_font_description_new;
|
|
with FontDialog.Font do
|
|
begin
|
|
pango_font_description_set_size(FontDesc, Size * PANGO_SCALE);
|
|
|
|
if fsBold in Style then
|
|
pango_font_description_set_weight(FontDesc, PANGO_WEIGHT_BOLD)
|
|
else
|
|
pango_font_description_set_weight(FontDesc, PANGO_WEIGHT_NORMAL);
|
|
|
|
if fsItalic in Style then
|
|
pango_font_description_set_style(FontDesc, PANGO_STYLE_ITALIC)
|
|
else
|
|
pango_font_description_set_style(FontDesc, PANGO_STYLE_NORMAL);
|
|
|
|
pango_font_description_set_family(FontDesc, PChar(Name));
|
|
end;
|
|
TmpStr := pango_font_description_to_string(FontDesc);
|
|
gtk_font_selection_dialog_set_font_name(PGtkFontSelectionDialog(Widget), TmpStr);
|
|
g_free(TmpStr);
|
|
pango_font_description_free(FontDesc);
|
|
{$ENDIF}
|
|
end;
|
|
|
|
{$IFDEF GTK1}
|
|
{ This functionality does not seem to be available in GTK2 }
|
|
// Honor selected TFontDialogOption flags
|
|
SpacingFilter := nil;
|
|
if fdFixedPitchOnly in FontDialog.Options then
|
|
SpacingFilter := @FixedFilter[0];
|
|
FontType := GTK_FONT_ALL;
|
|
if fdScalableOnly in FontDialog.Options then
|
|
FontType := GTK_FONT_SCALABLE;
|
|
gtk_font_selection_dialog_set_filter(PGtkFontSelectionDialog(Widget),
|
|
GTK_FONT_FILTER_BASE, FontType,
|
|
nil, nil, nil, nil, SpacingFilter, nil);
|
|
{$ENDIF}
|
|
|
|
Result := THandle(PtrUInt(Widget));
|
|
WidgetInfo := CreateWidgetInfo(Widget);
|
|
WidgetInfo^.LCLObject := ACommonDialog;
|
|
TGtkWSCommonDialog.SetSizes(Widget, WidgetInfo);
|
|
SetCallbacks(Widget, WidgetInfo);
|
|
end;
|
|
|
|
end.
|