1{ $Id$} 2{ 3 ***************************************************************************** 4 * Gtk2WSDialogs.pp * 5 * ---------------- * 6 * * 7 * * 8 ***************************************************************************** 9 10 ***************************************************************************** 11 This file is part of the Lazarus Component Library (LCL) 12 13 See the file COPYING.modifiedLGPL.txt, included in this distribution, 14 for details about the license. 15 ***************************************************************************** 16} 17unit Gtk2WSDialogs; 18 19{$mode objfpc}{$H+} 20 21interface 22 23uses 24 // RTL 25 Gtk2, Glib2, gdk2, pango, 26 SysUtils, Classes, 27 // LCL 28 Gtk2Extra, 29 Graphics, Controls, Dialogs, ExtDlgs, LCLType, 30 LazFileUtils, LazUTF8, LCLStrConsts, LCLProc, InterfaceBase, 31 // Widgetset 32 Gtk2Int, Gtk2Globals, Gtk2Def, Gtk2Proc, 33 WSDialogs; 34 35type 36 { TGtk2WSCommonDialog } 37 38 TGtk2WSCommonDialog = class(TWSCommonDialog) 39 private 40 class procedure SetColorDialogColor(ColorSelection: PGtkColorSelectionDialog; Color: TColor); 41 class procedure SetColorDialogPalette(ColorSelection: PGtkColorSelectionDialog; Palette: TStrings); 42 protected 43 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 44 class procedure SetSizes(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 45 published 46 class function CreateHandle(const {%H-}ACommonDialog: TCommonDialog): THandle; override; 47 class procedure ShowModal(const ACommonDialog: TCommonDialog); override; 48 class procedure DestroyHandle(const ACommonDialog: TCommonDialog); override; 49 end; 50 51 { TGtk2WSFileDialog } 52 53 TGtk2WSFileDialog = class(TWSFileDialog) 54 protected 55 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 56 published 57 class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override; 58 end; 59 60 { TGtk2WSOpenDialog } 61 62 TGtk2WSOpenDialog = class(TWSOpenDialog) 63 protected 64 class function CreateOpenDialogFilter(OpenDialog: TOpenDialog; SelWidget: PGtkWidget): string; virtual; 65 class procedure CreateOpenDialogHistory(OpenDialog: TOpenDialog; SelWidget: PGtkWidget); virtual; 66 class procedure CreatePreviewDialogControl(PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget); virtual; 67 published 68 class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override; 69 class function QueryWSEventCapabilities(const {%H-}ACommonDialog: TCommonDialog): TCDWSEventCapabilities; override; 70 end; 71 72 { TGtk2WSSaveDialog } 73 74 TGtk2WSSaveDialog = class(TWSSaveDialog) 75 published 76 class function QueryWSEventCapabilities(const {%H-}ACommonDialog: TCommonDialog): TCDWSEventCapabilities; override; 77 end; 78 79 { TGtk2WSSelectDirectoryDialog } 80 81 TGtk2WSSelectDirectoryDialog = class(TWSSelectDirectoryDialog) 82 published 83 class function QueryWSEventCapabilities(const {%H-}ACommonDialog: TCommonDialog): TCDWSEventCapabilities; override; 84 end; 85 86 { TGtk2WSColorDialog } 87 88 TGtk2WSColorDialog = class(TWSColorDialog) 89 protected 90 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 91 published 92 class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override; 93 class function QueryWSEventCapabilities(const {%H-}ACommonDialog: TCommonDialog): TCDWSEventCapabilities; override; 94 end; 95 96 { TGtk2WSColorButton } 97 98 TGtk2WSColorButton = class(TWSColorButton) 99 published 100 end; 101 102 { TGtk2WSFontDialog } 103 104 TGtk2WSFontDialog = class(TWSFontDialog) 105 protected 106 class procedure SetCallbacks(const AGtkWidget: PGtkWidget; const AWidgetInfo: PWidgetInfo); virtual; 107 published 108 class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override; 109 class function QueryWSEventCapabilities(const {%H-}ACommonDialog: TCommonDialog): TCDWSEventCapabilities; override; 110 end; 111 112// forward declarations 113 114procedure UpdateDetailView(OpenDialog: TOpenDialog); 115 116implementation 117 118{$I gtk2defines.inc} 119 120{------------------------------------------------------------------------------- 121 procedure UpdateDetailView 122 Params: OpenDialog: TOpenDialog 123 Result: none 124 125 Shows some OS dependent information about the current file 126-------------------------------------------------------------------------------} 127procedure UpdateDetailView(OpenDialog: TOpenDialog); 128var 129 FileDetailLabel: PGtkWidget; 130 Filename, OldFilename, Details: String; 131 Widget: PGtkWidget; 132begin 133 //DebugLn(['UpdateDetailView ']); 134 Widget := {%H-}PGtkWidget(OpenDialog.Handle); 135 FileName := gtk_file_chooser_get_filename(PGtkFileChooser(Widget)); 136 Filename:=SysToUTF8(Filename); 137 138 OldFilename := OpenDialog.Filename; 139 if Filename = OldFilename then 140 Exit; 141 OpenDialog.Filename := Filename; 142 // tell application, that selection has changed 143 OpenDialog.DoSelectionChange; 144 if (OpenDialog.OnFolderChange <> nil) and 145 (ExtractFilePath(Filename) <> ExtractFilePath(OldFilename)) then 146 OpenDialog.DoFolderChange; 147 // show some information 148 FileDetailLabel := g_object_get_data({%H-}PGObject(OpenDialog.Handle), 'FileDetailLabel'); 149 if FileDetailLabel = nil then 150 Exit; 151 if FileExistsUTF8(Filename) then 152 Details := GetFileDescription(Filename) 153 else 154 Details := Format(rsFileInfoFileNotFound, [Filename]); 155 gtk_label_set_text(PGtkLabel(FileDetailLabel), PChar(Details)); 156end; 157 158// ---------------------- signals ---------------------------------------------- 159 160procedure gtkFileChooserSelectionChangedCB({%H-}Chooser: PGtkFileChooser; 161 Data: Pointer); cdecl; 162var 163 theDialog: TFileDialog; 164begin 165 theDialog:=TFileDialog(Data); 166 if theDialog is TOpenDialog then 167 UpdateDetailView(TOpenDialog(theDialog)); 168end; 169 170procedure Gtk2FileChooserResponseCB(widget: PGtkFileChooser; arg1: gint; 171 data: gpointer); cdecl; 172 173 procedure AddFile(List: TStrings; const NewFile: string); 174 var 175 i: Integer; 176 begin 177 for i := 0 to List.Count-1 do 178 if List[i] = NewFile then 179 Exit; 180 List.Add(NewFile); 181 end; 182 183 function SkipDirectory(const AName: String): Boolean; 184 // gtk2-2.20 have problems. 185 // issue http://bugs.freepascal.org/view.php?id=17278 186 begin 187 Result := False; 188 if (gtk_major_version = 2) and (gtk_minor_version >= 20) and 189 (gtk_file_chooser_get_action(Widget) = GTK_FILE_CHOOSER_ACTION_OPEN) and 190 DirPathExists(AName) then 191 Result := True; 192 end; 193 194var 195 TheDialog: TFileDialog; 196 cFilename: PChar; 197 cFilenames: PGSList; 198 cFilenames1: PGSList; 199 Files: TStringList; 200 aFilename: String; 201begin 202 //DebugLn(['Gtk2FileChooserResponseCB ']); 203 theDialog := TFileDialog(data); 204 205 if arg1 = GTK_RESPONSE_CANCEL then 206 begin 207 TheDialog.UserChoice := mrCancel; 208 Exit; 209 end; 210 211 if theDialog is TOpenDialog then 212 begin 213 if ofAllowMultiSelect in TOpenDialog(theDialog).Options then 214 begin 215 TheDialog.FileName := ''; 216 Files := TStringList(TheDialog.Files); 217 Files.Clear; 218 cFilenames := gtk_file_chooser_get_filenames(widget); 219 if Assigned(cFilenames) then 220 begin 221 cFilenames1 := cFilenames; 222 while Assigned(cFilenames1) do 223 begin 224 cFilename := PChar(cFilenames1^.data); 225 if Assigned(cFilename) then 226 begin 227 aFilename:=SysToUTF8(cFilename); 228 if not SkipDirectory(aFileName) then 229 AddFile(Files, aFilename); 230 g_free(cFilename); 231 end; 232 cFilenames1 := cFilenames1^.next; 233 end; 234 g_slist_free(cFilenames); 235 end; 236 end 237 else 238 TheDialog.Files.Clear; 239 end; 240 241 cFilename := gtk_file_chooser_get_filename(widget); 242 243 if Assigned(cFilename) then 244 begin 245 aFilename:=SysToUTF8(cFilename); 246 if SkipDirectory(aFileName) then 247 TheDialog.FileName := '' 248 else 249 TheDialog.FileName := cFilename; 250 g_free(cFilename); 251 if (TheDialog is TOpenDialog) and (not (ofAllowMultiSelect in TOpenDialog(theDialog).Options)) then 252 TheDialog.Files.Add(TheDialog.FileName); 253 end; 254 255 //?? StoreCommonDialogSetup(theDialog); 256 theDialog.UserChoice := mrOK; 257end; 258 259procedure Gtk2FileChooserNotifyCB(dialog: PGObject; pspec: PGParamSpec; 260 user_data: gpointer); cdecl; 261var 262 TheDialog: TFileDialog; 263 GtkFilter: PGtkFileFilter; 264 GtkFilterList: PGSList; 265 NewFilterIndex: Integer; 266begin 267 //DebugLn(['Gtk2FileChooserNotifyCB ']); 268 if pspec^.name = 'filter' then 269 begin // filter changed 270 theDialog := TFileDialog(user_data); 271 GtkFilter := gtk_file_chooser_get_filter(dialog); 272 GtkFilterList := gtk_file_chooser_list_filters(dialog); 273 if (GtkFilter = nil) and (theDialog.Filter <> '') then 274 begin 275 // Either we don't have filter or gtk reset it. 276 // Gtk resets filter if we set both filename and filter but filename 277 // does not fit into filter. Gtk comparision has bug - it compares only by 278 // mime-type, not by pattern. LCL set all filters by pattern. 279 GtkFilter := g_slist_nth_data(GtkFilterList, theDialog.FilterIndex - 1); 280 gtk_file_chooser_set_filter(dialog, GtkFilter); 281 end 282 else 283 begin 284 NewFilterIndex := g_slist_index(GtkFilterList, GtkFilter); 285 theDialog.IntfFileTypeChanged(NewFilterIndex + 1); 286 end; 287 g_slist_free(GtkFilterList); 288 end; 289end; 290 291// ------------------------ Signals -------------------------------------------- 292 293{------------------------------------------------------------------------------- 294 function GTKDialogSelectRowCB 295 Params: widget: PGtkWidget; data: gPointer 296 Result: GBoolean 297 298 This function is called, whenever a row is selected in a commondialog 299-------------------------------------------------------------------------------} 300function gtkDialogSelectRowCB(widget: PGtkWidget; Row, Column: gInt; 301 bevent: pgdkEventButton; data: gPointer): GBoolean; cdecl; 302var 303 theDialog: TCommonDialog; 304 MenuWidget: PGtkWidget; 305 AFilterEntry: TFileSelFilterEntry; 306 FileSelWidget: PGtkFileSelection; 307 ShiftState: TShiftState; 308 loop : gint; 309 startRow : gint; 310 endRow : gint; 311begin 312 //debugln('GTKDialogSelectRowCB A '); 313 Result:=CallBackDefaultReturn; 314 if (Data=nil) or (BEvent=nil) or (Column=0) or (Row=0) then ; 315 theDialog:=TCommonDialog(GetLCLObject(Widget)); 316 if (theDialog is TOpenDialog) then begin 317 // only process the callback if there is event data. If there isn't any 318 // event data that means it was called due to a direct function call of the 319 // widget and not an actual mouse click on the widget. 320 FileSelWidget:={%H-}PGtkFileSelection(theDialog.Handle); 321 if (bevent <> nil) and (gdk_event_get_type(bevent) = GDK_2BUTTON_PRESS) 322 and (FileSelWidget^.dir_list = widget) then begin 323 MenuWidget := g_object_get_data(PGObject(FileSelWidget), 324 'LCLFilterMenu'); 325 if MenuWidget <> nil then begin 326 AFilterEntry := TFileSelFilterEntry(g_object_get_data(PGObject( 327 gtk_menu_get_active(PGtkMenu(MenuWidget))), 'LCLIsFilterMenuItem')); 328 if (AFilterEntry<>nil) and (AFilterEntry.Mask<>nil) then 329 PopulateFileAndDirectoryLists(FileSelWidget,AFilterEntry.Mask); 330 end; 331 end 332 else if (bevent <> nil) 333 and (ofAllowMultiSelect in TOpenDialog(theDialog).Options) 334 and (FileSelWidget^.file_list=widget) then begin 335 // multi selection 336 ShiftState := GTKEventStateToShiftState(BEvent^.State); 337 if ssShift in ShiftState then begin 338 if LastFileSelectRow <> -1 then begin 339 startRow := LastFileSelectRow; 340 endRow := row; 341 if LastFileSelectRow > row then begin 342 startRow := row; 343 endRow := LastFileSelectRow; 344 end; 345 for loop := startRow to endRow do begin 346 gtk_clist_select_row(PGtkCList(widget), loop, column); 347 end; 348 end; 349 end 350 else if not (ssCtrl in ShiftState) then begin 351 gtk_clist_unselect_all(PGtkCList(widget)); 352 gtk_clist_select_row(PGtkCList(widget), row, column); 353 end; 354 LastFileSelectRow := row; 355 end; 356 UpdateDetailView(TOpenDialog(theDialog)); 357 end; 358end; 359 360{------------------------------------------------------------------------------- 361 function gtkDialogHelpclickedCB 362 Params: widget: PGtkWidget; data: gPointer 363 Result: GBoolean 364 365 This function is called, whenever the user clicks the help button in a 366 commondialog 367-------------------------------------------------------------------------------} 368function gtkDialogHelpclickedCB(widget: PGtkWidget; data: gPointer): GBoolean; cdecl; 369var 370 theDialog : TCommonDialog; 371begin 372 Result := CallBackDefaultReturn; 373 if (Widget=nil) then ; 374 theDialog := TCommonDialog(data); 375 if theDialog is TOpenDialog then begin 376 if TOpenDialog(theDialog).OnHelpClicked<>nil then 377 TOpenDialog(theDialog).OnHelpClicked(theDialog); 378 end; 379end; 380 381{------------------------------------------------------------------------------- 382 function gtkDialogApplyclickedCB 383 Params: widget: PGtkWidget; data: gPointer 384 Result: GBoolean 385 386 This function is called, whenever the user clicks the Apply button in a 387 commondialog 388-------------------------------------------------------------------------------} 389function gtkDialogApplyclickedCB(widget: PGtkWidget; data: gPointer): GBoolean; 390 cdecl; 391var 392 theDialog : TCommonDialog; 393 FontName: string; 394 ALogFont: TLogFont; 395 396 FontDesc: PPangoFontDescription; 397begin 398 Result := CallBackDefaultReturn; 399 if (Widget=nil) then ; 400 theDialog := TCommonDialog(data); 401 if (theDialog is TFontDialog) 402 and (fdApplyButton in TFontDialog(theDialog).Options) 403 and (Assigned(TFontDialog(theDialog).OnApplyClicked)) then begin 404 FontName := gtk_font_selection_dialog_get_font_name( 405 {%H-}pgtkfontselectiondialog(theDialog.Handle)); 406 if IsFontNameXLogicalFontDesc(FontName) then begin 407 // extract basic font attributes from the font name in XLFD format 408 ALogFont:=XLFDNameToLogFont(FontName); 409 TFontDialog(theDialog).Font.Assign(ALogFont); 410 // set the font name in XLFD format 411 // a font name in XLFD format overrides in the gtk interface all other font 412 // settings. 413 TFontDialog(theDialog).Font.Name := FontName; 414 end else begin 415 FontDesc := pango_font_description_from_string(PChar(FontName)); 416 with TFontDialog(theDialog).Font do 417 begin 418 BeginUpdate; 419 Size := pango_font_description_get_size(FontDesc) div PANGO_SCALE; 420 if pango_font_description_get_weight(FontDesc) >= PANGO_WEIGHT_BOLD then 421 Style := Style + [fsBold] 422 else 423 Style := Style - [fsBold]; 424 if pango_font_description_get_style(FontDesc) > PANGO_STYLE_NORMAL then 425 Style := Style + [fsItalic] 426 else 427 Style := Style - [fsItalic]; 428 Name := pango_font_description_get_family(FontDesc); 429 EndUpdate; 430 end; 431 pango_font_description_free(FontDesc); 432 end; 433 TFontDialog(theDialog).OnApplyClicked(theDialog); 434 end; 435end; 436 437function gtkDialogOKclickedCB( widget: PGtkWidget; data: gPointer) : GBoolean; cdecl; 438var 439 theDialog : TCommonDialog; 440 Fpointer : Pointer; 441 // colordialog 442 colorsel : PGtkColorSelection; 443 newColor : TGdkColor; 444 // fontdialog 445 FontName : String; 446 ALogFont : TLogFont; 447 // filedialog 448 rowNum : gint; 449 fileInfo : PGChar; 450 451 fileList : PPgchar; 452 FontDesc: PPangoFontDescription; 453 454 DirName : string; 455 FileName : string; 456 Files: TStringList; 457 CurFilename: string; 458 //SelectedFont: PGdkFont; 459 460 function CheckOpenedFilename(var AFilename: string): boolean; 461 begin 462 Result:=true; 463 464 // maybe file already exists 465 if (ofOverwritePrompt in TOpenDialog(theDialog).Options) 466 and FileExistsUTF8(AFilename) then 467 begin 468 Result := MessageDlg(rsfdOverwriteFile, 469 Format(rsfdFileAlreadyExists,[AFileName]), 470 mtConfirmation,[mbOk,mbCancel],0)=mrOk; 471 if not Result then exit; 472 end; 473 end; 474 475 procedure AddFile(List: TStrings; const NewFile: string); 476 var 477 i: Integer; 478 begin 479 for i:=0 to List.Count-1 do 480 if List[i]=NewFile then exit; 481 List.Add(NewFile); 482 end; 483 484begin 485 Result := True; 486 if (Widget=nil) then ; 487 theDialog := TCommonDialog(data); 488 FPointer := {%H-}Pointer(theDialog.Handle); 489 490 if theDialog is TFileDialog then 491 begin 492 FileName:=gtk_file_chooser_get_filename(PGtkFileChooser(FPointer)); 493 FileName:=SysToUTF8(Filename); 494 495 if theDialog is TOpenDialog then 496 begin 497 // check extra options 498 if ofAllowMultiSelect in TOpenDialog(theDialog).Options then 499 begin 500 DirName:=ExtractFilePath(FileName); 501 TFileDialog(data).FileName := ''; 502 Files:=TStringList(TFileDialog(theDialog).Files); 503 Files.Clear; 504 if (Filename<>'') then begin 505 Result:=CheckOpenedFilename(Filename); 506 if not Result then exit; 507 AddFile(Files,FileName); 508 end; 509 510 fileList := gtk_file_selection_get_selections(PGtkFileSelection(FPointer)); 511 rowNum := 0; 512 While FileList^ <> nil do 513 begin 514 fileInfo := FileList^; 515 CurFilename:=fileInfo; // convert PChar to AnsiString (not typecast) 516 CurFilename:=SysToUTF8(CurFilename); 517 if (CurFilename<>'') and (Files.IndexOf(CurFilename)<0) then begin 518 CurFilename:=DirName+fileInfo; 519 Result:=CheckOpenedFilename(CurFilename); 520 if not Result then exit; 521 Files.Add(CurFilename); 522 end; 523 inc(FileList); 524 inc(rowNum); 525 end; 526 Dec(FileList, rowNum); 527 g_strfreev(fileList); 528 end 529 else 530 begin 531 Result:=CheckOpenedFilename(Filename); 532 if not Result then exit; 533 TFileDialog(data).FileName := Filename; 534 end; 535 end 536 else 537 begin 538 TFileDialog(data).FileName := Filename; 539 end; 540 end 541 else if theDialog is TColorDialog then 542 begin 543 colorSel := PGtkColorSelection(PGtkColorSelectionDialog(FPointer)^.colorsel); 544 gtk_color_selection_get_current_color(colorsel, @newColor); 545 TColorDialog(theDialog).Color := TGDKColorToTColor(newcolor); 546 {$IFDEF VerboseColorDialog} 547 DebugLn('gtkDialogOKclickedCB ',DbgS(TColorDialog(theDialog).Color)); 548 {$ENDIF} 549 end 550 else if theDialog is TFontDialog then 551 begin 552 //DebugLn('Trace:Pressed OK in FontDialog'); 553 FontName := gtk_font_selection_dialog_get_font_name( 554 pgtkfontselectiondialog(FPointer)); 555 //debugln('gtkDialogOKclickedCB FontName=',FontName); 556 //SelectedFont:=gdk_font_load(PChar(FontName)); 557 //debugln('gtkDialogOKclickedCB ',dbgs(SelectedFont)); 558 559 if IsFontNameXLogicalFontDesc(FontName) then 560 begin 561 // extract basic font attributes from the font name in XLFD format 562 ALogFont:=XLFDNameToLogFont(FontName); 563 TFontDialog(theDialog).Font.Assign(ALogFont); 564 // set the font name in XLFD format 565 // a font name in XLFD format overrides in the gtk interface all other font 566 // settings. 567 TFontDialog(theDialog).Font.Name := FontName; 568 end 569 else 570 begin 571 FontDesc := pango_font_description_from_string(PChar(FontName)); 572 with TFontDialog(theDialog).Font do 573 begin 574 BeginUpdate; 575 Size := pango_font_description_get_size(FontDesc) div PANGO_SCALE; 576 if pango_font_description_get_weight(FontDesc) >= PANGO_WEIGHT_BOLD then 577 Style := Style + [fsBold] 578 else 579 Style := Style - [fsBold]; 580 if pango_font_description_get_style(FontDesc) > PANGO_STYLE_NORMAL then 581 Style := Style + [fsItalic] 582 else 583 Style := Style - [fsItalic]; 584 Name := pango_font_description_get_family(FontDesc); 585 EndUpdate; 586 end; 587 pango_font_description_free(FontDesc); 588 end; 589 590 //DebugLn('Trace:-----'+TFontDialog(theDialog).Font.Name+'----'); 591 end; 592 593 StoreCommonDialogSetup(theDialog); 594 theDialog.UserChoice := mrOK; 595end; 596 597{------------------------------------------------------------------------------- 598 function gtkDialogCancelclickedCB 599 Params: widget: PGtkWidget; data: gPointer 600 Result: GBoolean 601 602 This function is called, whenever the user clicks the cancel button in a 603 commondialog 604-------------------------------------------------------------------------------} 605function gtkDialogCancelclickedCB(widget: PGtkWidget; data: gPointer): GBoolean; 606 cdecl; 607var 608 theDialog : TCommonDialog; 609begin 610 Result := CallBackDefaultReturn; 611 if (Widget=nil) then ; 612 theDialog := TCommonDialog(data); 613 if theDialog is TFileDialog then 614 begin 615 TFileDialog(data).FileName := ''; 616 end; 617 StoreCommonDialogSetup(theDialog); 618 theDialog.UserChoice := mrCancel; 619end; 620 621{------------------------------------------------------------------------------- 622 function GTKDialogRealizeCB 623 Params: Widget: PGtkWidget; Data: Pointer 624 Result: GBoolean 625 626 This function is called, whenever a commondialog window is realized 627-------------------------------------------------------------------------------} 628function GTKDialogRealizeCB(Widget: PGtkWidget; Data: Pointer): GBoolean; cdecl; 629var 630 LCLComponent: TObject; 631begin 632 if (Data=nil) then ; 633 gdk_window_set_events(GetControlWindow(Widget), 634 gdk_window_get_events(GetControlWindow(Widget)) 635 or GDK_KEY_RELEASE_MASK or GDK_KEY_PRESS_MASK); 636 LCLComponent:=GetLCLObject(Widget); 637 if LCLComponent is TCommonDialog then 638 begin 639 {$ifdef DebugCommonDialogEvents} 640 debugln(['GTKDialogRealizeCB calling DoShow']); 641 {$endif} 642 TCommonDialog(LCLComponent).DoShow; 643 end; 644 Result:=true; 645end; 646 647{------------------------------------------------------------------------------- 648 function gtkDialogCloseQueryCB 649 Params: widget: PGtkWidget; data: gPointer 650 Result: GBoolean 651 652 This function is called, before a commondialog is destroyed 653 (Only when the user aborts the dialog, not if the dialog closes as the result 654 of a click on one of itś buttons) 655-------------------------------------------------------------------------------} 656function gtkDialogCloseQueryCB(widget: PGtkWidget; data: gPointer): GBoolean; 657 cdecl; 658var 659 theDialog : TCommonDialog; 660 CanClose: boolean; 661begin 662 {$ifdef DebugCommonDialogEvents} 663 debugln(['>>>>gtkDialogCloseQueryCB A']); 664 {$endif} 665 Result := False; // true = do nothing, false = destroy or hide window 666 if (Data=nil) then ; 667 // data is not the commondialog. Get it manually. 668 theDialog := TCommonDialog(GetLCLObject(Widget)); 669 if theDialog=nil then exit; 670 if theDialog.OnCanClose<>nil then begin 671 theDialog.UserChoice := mrCancel; 672 CanClose:=True; 673 {$ifdef DebugCommonDialogEvents} 674 debugln(['gtkDialogCloseQueryCB calling DoCanClose']); 675 {$endif} 676 theDialog.DoCanClose(CanClose); 677 Result:=not CanClose; 678 end; 679 if not Result then begin 680 StoreCommonDialogSetup(theDialog); 681 DestroyCommonDialogAddOns(theDialog); 682 end; 683 {$ifdef DebugCommonDialogEvents} 684 debugln(['gtkDialogCloseQueryCB End']); 685 {$endif} 686end; 687 688{------------------------------------------------------------------------------- 689 function gtkDialogDestroyCB 690 Params: widget: PGtkWidget; data: gPointer 691 Result: GBoolean 692 693 This function is called, when a commondialog is destroyed 694-------------------------------------------------------------------------------} 695function gtkDialogDestroyCB(widget: PGtkWidget; data: gPointer): GBoolean; cdecl; 696begin 697 {$ifdef DebugCommonDialogEvents} 698 debugln(['gtkDialogDestroyCB A']); 699 {$endif} 700 Result := True; 701 if (Widget=nil) then ; 702 TCommonDialog(data).UserChoice := mrCancel; 703 TCommonDialog(data).Close; 704 {$ifdef DebugCommonDialogEvents} 705 debugln(['gtkDialogDestroyCB End']); 706 {$endif} 707end; 708 709{------------------------------------------------------------------------------- 710 function GTKDialogKeyUpDownCB 711 Params: Widget: PGtkWidget; Event : pgdkeventkey; Data: gPointer 712 Result: GBoolean 713 714 This function is called, whenever a key is pressed or released in a common 715 dialog window 716-------------------------------------------------------------------------------} 717function GTKDialogKeyUpDownCB(Widget: PGtkWidget; Event : pgdkeventkey; 718 Data: gPointer) : GBoolean; cdecl; 719begin 720 Result:=CallBackDefaultReturn; 721 722 if (Widget=nil) then ; 723 case gdk_event_get_type(Event) of 724 725 GDK_KEY_RELEASE, GDK_KEY_PRESS: 726 begin 727 if Event^.KeyVal = GDK_KEY_Escape 728 then begin 729 StoreCommonDialogSetup(TCommonDialog(data)); 730 TCommonDialog(data).UserChoice:=mrCancel; 731 end; 732 if (TCommonDialog(data) is TOpenDialog) then begin 733 UpdateDetailView(TOpenDialog(data)); 734 end; 735 end; 736 737 end; 738end; 739 740{------------------------------------------------------------------------------- 741 function GTKDialogFocusInCB 742 Params: widget: PGtkWidget; data: gPointer 743 Result: GBoolean 744 745 This function is called, when a widget of a commondialog gets focus 746-------------------------------------------------------------------------------} 747function GTKDialogFocusInCB(widget: PGtkWidget; data: gPointer): GBoolean; 748 cdecl; 749var 750 theDialog: TCommonDialog; 751begin 752 //debugln('GTKDialogFocusInCB A '); 753 Result:=CallBackDefaultReturn; 754 if (Data=nil) then ; 755 theDialog:=TCommonDialog(GetLCLObject(Widget)); 756 if (theDialog is TOpenDialog) then begin 757 UpdateDetailView(TOpenDialog(theDialog)); 758 end; 759end; 760 761{------------------------------------------------------------------------------- 762 function GTKDialogMenuActivateCB 763 Params: widget: PGtkWidget; data: gPointer 764 Result: GBoolean 765 766 This function is called, whenever a menu of a commondialog is activated 767-------------------------------------------------------------------------------} 768function GTKDialogMenuActivateCB(widget: PGtkWidget; data: gPointer): GBoolean; 769 cdecl; 770var 771 theDialog: TCommonDialog; 772 773 procedure CheckFilterActivated(FilterWidget: PGtkWidget); 774 var 775 AFilterEntry: TFileSelFilterEntry; 776 begin 777 if FilterWidget=nil then exit; 778 AFilterEntry:=TFileSelFilterEntry(g_object_get_data(PGObject(FilterWidget), 779 'LCLIsFilterMenuItem')); 780 if (AFilterEntry<>nil) and (AFilterEntry.Mask<>nil) then 781 begin 782 PopulateFileAndDirectoryLists({%H-}PGtkFileSelection(theDialog.Handle), 783 AFilterEntry.Mask); 784 TFileDialog(TheDialog).IntfFileTypeChanged(AFilterEntry.FilterIndex + 1); 785 UpdateDetailView(TOpenDialog(theDialog)); 786 end; 787 end; 788 789var 790 AHistoryEntry: PFileSelHistoryEntry; 791 aSysFilename: String; 792begin 793 Result:=false; 794 if (Data=nil) then ; 795 theDialog:=TCommonDialog(GetNearestLCLObject(Widget)); 796 if (theDialog is TOpenDialog) then begin 797 // check if history activated 798 AHistoryEntry:=g_object_get_data(PGObject(Widget), 799 'LCLIsHistoryMenuItem'); 800 if (AHistoryEntry<>nil) and (AHistoryEntry^.Filename<>nil) then begin 801 // user has choosen a history file 802 // -> select it in the filedialog 803 aSysFilename:=UTF8ToSys(AHistoryEntry^.Filename); 804 gtk_file_chooser_set_current_folder({%H-}PGtkFileChooser(theDialog.Handle), 805 Pgchar(aSysFilename)); 806 807 UpdateDetailView(TOpenDialog(theDialog)); 808 end; 809 end; 810end; 811 812{ TGtk2WSSelectDirectoryDialog } 813 814class function TGtk2WSSelectDirectoryDialog.QueryWSEventCapabilities( 815 const ACommonDialog: TCommonDialog): TCDWSEventCapabilities; 816begin 817 Result := [cdecWSPerformsDoShow]; 818end; 819 820{ TGtk2WSSaveDialog } 821 822class function TGtk2WSSaveDialog.QueryWSEventCapabilities( 823 const ACommonDialog: TCommonDialog): TCDWSEventCapabilities; 824begin 825 Result := [cdecWSPerformsDoShow]; 826end; 827 828// ---------------------- END OF signals --------------------------------------- 829 830{ TGtk2WSOpenDialog } 831 832class function TGtk2WSOpenDialog.CreateOpenDialogFilter( 833 OpenDialog: TOpenDialog; SelWidget: PGtkWidget): string; 834var 835 ListOfFileSelFilterEntry: TFPList; 836 i, j, k: integer; 837 GtkFilter, GtkSelFilter: PGtkFileFilter; 838 MaskList: TStringList; 839 FilterEntry: TFileSelFilterEntry; 840 FilterIndex: Integer; 841 aMask: String; 842begin 843 FilterIndex := OpenDialog.FilterIndex; 844 ExtractFilterList(OpenDialog.Filter, ListOfFileSelFilterEntry, false); 845 GtkSelFilter := nil; 846 if ListOfFileSelFilterEntry.Count > 0 then 847 begin 848 j := 1; 849 MaskList := TStringList.Create; 850 MaskList.Delimiter := ';'; 851 for i := 0 to ListOfFileSelFilterEntry.Count-1 do 852 begin 853 GtkFilter := gtk_file_filter_new(); 854 855 FilterEntry := TFileSelFilterEntry(ListOfFileSelFilterEntry[i]); 856 MaskList.DelimitedText := FilterEntry.Mask; 857 858 for k := 0 to MaskList.Count - 1 do begin 859 aMask:=UTF8ToSys(MaskList.Strings[k]); 860 gtk_file_filter_add_pattern(GtkFilter, PChar(aMask)); 861 end; 862 863 gtk_file_filter_set_name(GtkFilter, FilterEntry.Description); 864 865 gtk_file_chooser_add_filter(SelWidget, GtkFilter); 866 867 if j = FilterIndex then 868 GtkSelFilter := GtkFilter; 869 870 Inc(j); 871 GtkFilter := nil; 872 end; 873 MaskList.Free; 874 end; 875 876 FreeListOfFileSelFilterEntry(ListOfFileSelFilterEntry); 877 //g_object_set_data(PGObject(SelWidget), 'LCLFilterList', ListOfFileSelFilterEntry); 878 879 if GtkSelFilter <> nil then 880 gtk_file_chooser_set_filter(SelWidget, GtkSelFilter); 881 882 Result := 'hm'; { Don't use '' as null return as this is used for *.* } 883end; 884 885class procedure TGtk2WSOpenDialog.CreateOpenDialogHistory( 886 OpenDialog: TOpenDialog; SelWidget: PGtkWidget); 887var 888 HistoryList: TFPList; // list of THistoryListEntry 889 AHistoryEntry: PFileSelHistoryEntry; 890 i: integer; 891 s: string; 892 HBox, LabelWidget, HistoryPullDownWidget, 893 MenuWidget, MenuItemWidget: PGtkWidget; 894begin 895 if OpenDialog.HistoryList.Count>0 then begin 896 897 // create the HistoryList where the current state of the history is stored 898 HistoryList:=TFPList.Create; 899 for i:=0 to OpenDialog.HistoryList.Count-1 do begin 900 s:=OpenDialog.HistoryList[i]; 901 if s<>'' then begin 902 New(AHistoryEntry); 903 HistoryList.Add(AHistoryEntry); 904 AHistoryEntry^.Filename := StrAlloc(length(s)+1); 905 StrPCopy(AHistoryEntry^.Filename, s); 906 AHistoryEntry^.MenuItem:=nil; 907 end; 908 end; 909 910 // create a HBox so that the history is left justified 911 HBox:=gtk_hbox_new(false,0); 912 g_object_set_data(PGObject(SelWidget), 'LCLHistoryHBox', HBox); 913 gtk_file_chooser_set_extra_widget(PGtkDialog(SelWidget),HBox); 914 915 // create the label 'History:' 916 s:=rsgtkHistory; 917 LabelWidget:=gtk_label_new(PChar(s)); 918 gtk_box_pack_start(GTK_BOX(HBox),LabelWidget,false,false,5); 919 gtk_widget_show(LabelWidget); 920 921 // create the pull down 922 HistoryPullDownWidget:=gtk_option_menu_new; 923 g_object_set_data(PGObject(SelWidget), 'LCLHistoryPullDown', 924 HistoryPullDownWidget); 925 gtk_box_pack_start(GTK_BOX(HBox),HistoryPullDownWidget,false,false,5); 926 gtk_widget_show(HistoryPullDownWidget); 927 gtk_widget_show_all(HBox); 928 929 // create the menu (the content of the pull down) 930 MenuWidget:=gtk_menu_new; 931 SetLCLObject(MenuWidget,OpenDialog); 932 for i:=0 to HistoryList.Count-1 do begin 933 // create the menu items in the history menu 934 MenuItemWidget:=gtk_menu_item_new_with_label( 935 PFileSelHistoryEntry(HistoryList[i])^.Filename); 936 // connect the new MenuItem to the HistoryList entry 937 g_object_set_data(PGObject(MenuItemWidget), 'LCLIsHistoryMenuItem', 938 HistoryList[i]); 939 // add activation signal and add to menu 940 g_signal_connect(GTK_OBJECT(MenuItemWidget), 'activate', 941 gtk_signal_func(@GTKDialogMenuActivateCB), 942 OpenDialog); 943 gtk_menu_append(MenuWidget, MenuItemWidget); 944 gtk_widget_show(MenuItemWidget); 945 end; 946 gtk_widget_show(MenuWidget); 947 gtk_option_menu_set_menu(GTK_OPTION_MENU(HistoryPullDownWidget), 948 MenuWidget); 949 end else begin 950 MenuWidget:=nil; 951 HistoryList:=nil 952 end; 953 g_object_set_data(PGObject(SelWidget), 'LCLHistoryMenu', MenuWidget); 954 g_object_set_data(PGObject(SelWidget), 'LCLHistoryList', HistoryList); 955end; 956 957class procedure TGtk2WSOpenDialog.CreatePreviewDialogControl( 958 PreviewDialog: TPreviewFileDialog; SelWidget: PGtkWidget); 959var 960 PreviewWidget: PGtkWidget; 961 AControl: TPreviewFileControl; 962 Win, SubWin: TWinControl; 963 FileChooser: PGtkFileChooser; 964begin 965 AControl := PreviewDialog.PreviewFileControl; 966 if AControl = nil then Exit; 967 968 FileChooser := PGtkFileChooser(SelWidget); 969 970 PreviewWidget := {%H-}PGtkWidget(AControl.Handle); 971 972 g_object_set_data(PGObject(PreviewWidget),'LCLPreviewFixed', 973 PreviewWidget); 974 gtk_widget_set_size_request(PreviewWidget,AControl.Width,AControl.Height); 975 976 // manually resize the preview objects, it seems, automatic resize is not 977 // working when parent of LCL control is not a LCL control. 978 if (AControl.ControlCount>0) and (AControl.Controls[0] is TWinControl) then begin 979 Win := TWinControl(AControl.Controls[0]); // groupbox 980 SubWin := TWinControl(Win.Controls[0]); // image 981 gtk_widget_set_size_request({%H-}PGtkWidget(Win.Handle), AControl.Width, AControl.Height); 982 SubWin.width := AControl.Width-4; // skip borders 983 SubWin.height := AControl.Height-15; // 984 end; 985 986 gtk_file_chooser_set_preview_widget(FileChooser, PreviewWidget); 987end; 988 989{ 990 Adds some functionality to a gtk file selection dialog. 991 - multiselection 992 - range selection 993 - close on escape 994 - file information 995 - history pulldown 996 - filter pulldown 997 - preview control 998 999 requires: gtk+ 2.6 1000} 1001class function TGtk2WSOpenDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle; 1002var 1003 FileSelWidget: PGtkFileChooser; 1004 OpenDialog: TOpenDialog absolute ACommonDialog; 1005 HelpButton: PGtkWidget; 1006 InitialFilename: String; 1007 aSysFilename: String; 1008 //FrameWidget: PGtkWidget; 1009 //HBox: PGtkWidget; 1010 //FileDetailLabel: PGtkWidget; 1011begin 1012 Result := TGtk2WSFileDialog.CreateHandle(ACommonDialog); 1013 FileSelWidget := {%H-}PGtkFileChooser(Result); 1014 1015 if OpenDialog.InheritsFrom(TSaveDialog) then 1016 begin 1017 if OpenDialog.InitialDir <> '' then begin 1018 aSysFilename:=UTF8ToSys(OpenDialog.InitialDir); 1019 gtk_file_chooser_set_current_folder(FileSelWidget, Pgchar(aSysFilename)); 1020 end; 1021 end; 1022 1023 // Help button 1024 if (ofShowHelp in OpenDialog.Options) then 1025 begin 1026 HelpButton := gtk_dialog_add_button(FileSelWidget, GTK_STOCK_HELP, GTK_RESPONSE_NONE); 1027 1028 g_signal_connect(PGtkObject(HelpButton), 1029 'clicked', gtk_signal_func(@gtkDialogHelpclickedCB), OpenDialog); 1030 end; 1031 1032 if ofAllowMultiSelect in OpenDialog.Options then 1033 gtk_file_chooser_set_select_multiple(FileSelWidget, gboolean(gtrue)); 1034 1035 // History List - a frame with an option menu 1036 CreateOpenDialogHistory(OpenDialog, FileSelWidget); 1037 1038 // Filter 1039 CreateOpenDialogFilter(OpenDialog, FileSelWidget); 1040 1041 // connect change event 1042 g_signal_connect(PGtkObject(FileSelWidget), 1043 'selection-changed', gtk_signal_func(@gtkFileChooserSelectionChangedCB), 1044 OpenDialog); 1045 1046 // Sets the dialog options 1047 1048 // ofForceShowHidden 1049 if (ofForceShowHidden in OpenDialog.Options) then 1050 gtk_file_chooser_set_show_hidden(FileSelWidget, True); 1051 1052 (* TODO 1053 // Details - a frame with a label 1054 if (ofViewDetail in OpenDialog.Options) then begin 1055 1056 // create the frame around the information 1057 FrameWidget:=gtk_frame_new(PChar(rsFileInformation)); 1058 //gtk_box_pack_start(GTK_BOX(FileSelWidget^.main_vbox), 1059 // FrameWidget,false,false,0); 1060 gtk_box_pack_start(GTK_BOX(gtk_file_chooser_get_extra_widget( 1061 PGtkFileChooser(SelWidget))), FrameWidget,false,false,0); 1062 gtk_widget_show(FrameWidget); 1063 // create a HBox, so that the information is left justified 1064 HBox:=gtk_hbox_new(false,0); 1065 gtk_container_add(GTK_CONTAINER(FrameWidget), HBox); 1066 // create the label for the file information 1067 FileDetailLabel:=gtk_label_new(PChar(rsDefaultFileInfoValue)); 1068 gtk_box_pack_start(GTK_BOX(HBox),FileDetailLabel,false,false,5); 1069 gtk_widget_show_all(HBox); 1070 end else 1071 FileDetailLabel:=nil; 1072 g_object_set_data(PGObject(SelWidget), 'FileDetailLabel', 1073 FileDetailLabel); 1074 *) 1075 // preview 1076 if (OpenDialog is TPreviewFileDialog) then 1077 CreatePreviewDialogControl(TPreviewFileDialog(OpenDialog), PGtkWidget(FileSelWidget)); 1078 1079 // set initial filename (gtk expects an absolute filename) 1080 InitialFilename := TrimFilename(OpenDialog.FileName); 1081 if InitialFilename <> '' then 1082 begin 1083 if not FilenameIsAbsolute(InitialFilename) and (OpenDialog.InitialDir <> '') then 1084 InitialFilename := TrimFilename(OpenDialog.InitialDir + PathDelim + InitialFilename); 1085 if not FilenameIsAbsolute(InitialFilename) then 1086 InitialFilename := CleanAndExpandFilename(InitialFilename); 1087 aSysFilename:=UTF8ToSys(InitialFilename); 1088 gtk_file_chooser_set_filename(FileSelWidget, PChar(aSysFilename)); 1089 end; 1090 1091 //if InitialFilter <> 'none' then 1092 // PopulateFileAndDirectoryLists(FileSelWidget, InitialFilter); 1093end; 1094 1095class function TGtk2WSOpenDialog.QueryWSEventCapabilities( 1096 const ACommonDialog: TCommonDialog): TCDWSEventCapabilities; 1097begin 1098 Result := [cdecWSPerformsDoShow]; 1099end; 1100 1101{ TGtk2WSFileDialog } 1102 1103class procedure TGtk2WSFileDialog.SetCallbacks(const AGtkWidget: PGtkWidget; 1104 const AWidgetInfo: PWidgetInfo); 1105begin 1106 TGtk2WSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo); 1107 g_signal_connect(AGtkWidget, 'response', gtk_signal_func(@Gtk2FileChooserResponseCB), AWidgetInfo^.LCLObject); 1108 g_signal_connect(AGtkWidget, 'notify', gtk_signal_func(@Gtk2FileChooserNotifyCB), AWidgetInfo^.LCLObject); 1109end; 1110 1111{ 1112 Creates a new TFile/Open/SaveDialog 1113 requires: gtk+ 2.6 1114} 1115class function TGtk2WSFileDialog.CreateHandle(const ACommonDialog: TCommonDialog 1116 ): THandle; 1117var 1118 FileDialog: TFileDialog absolute ACommonDialog; 1119 Action: TGtkFileChooserAction; 1120 Button1: String; 1121 Widget: PGtkWidget; 1122 WidgetInfo: PWidgetInfo; 1123 aSysFilename: String; 1124begin 1125 // Defines an action for the dialog and creates it 1126 Action := GTK_FILE_CHOOSER_ACTION_OPEN; 1127 Button1 := GTK_STOCK_OPEN; 1128 1129 if (FileDialog is TSaveDialog) or (FileDialog is TSavePictureDialog) then 1130 begin 1131 Action := GTK_FILE_CHOOSER_ACTION_SAVE; 1132 Button1 := GTK_STOCK_SAVE; 1133 end 1134 else 1135 if FileDialog is TSelectDirectoryDialog then 1136 begin 1137 Action := GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER; 1138 Button1 := GTK_STOCK_OPEN; 1139 end; 1140 1141 Widget := gtk_file_chooser_dialog_new(PChar(FileDialog.Title), nil, Action, 1142 PChar(GTK_STOCK_CANCEL), [GTK_RESPONSE_CANCEL, PChar(Button1), GTK_RESPONSE_OK, nil]); 1143 1144 {$ifdef GTK_2_8} 1145 if FileDialog is TSaveDialog then 1146 begin 1147 gtk_file_chooser_set_do_overwrite_confirmation(Widget, 1148 ofOverwritePrompt in TOpenDialog(FileDialog).Options); 1149 end; 1150 {$endif} 1151 1152 if FileDialog.InitialDir <> '' then begin 1153 aSysFilename:=UTF8ToSys(FileDialog.InitialDir); 1154 gtk_file_chooser_set_current_folder(Widget, Pgchar(aSysFilename)); 1155 end; 1156 1157 if gtk_file_chooser_get_action(Widget) in 1158 [GTK_FILE_CHOOSER_ACTION_SAVE, GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER] 1159 then 1160 gtk_file_chooser_set_current_name(Widget, Pgchar(FileDialog.FileName)); 1161 1162 Result := THandle({%H-}PtrUInt(Widget)); 1163 WidgetInfo := CreateWidgetInfo(Widget); 1164 WidgetInfo^.LCLObject := ACommonDialog; 1165 TGtk2WSCommonDialog.SetSizes(Widget, WidgetInfo); 1166 SetCallbacks(Widget, WidgetInfo); 1167end; 1168 1169{ TGtk2WSCommonDialog } 1170 1171{------------------------------------------------------------------------------ 1172 Method: SetColorDialogColor 1173 Params: ColorSelection : a gtk color selection dialog; 1174 Color : the color to select 1175 Returns: nothing 1176 1177 Set the color of the color selection dialog 1178 ------------------------------------------------------------------------------} 1179class procedure TGtk2WSCommonDialog.SetColorDialogColor(ColorSelection: PGtkColorSelectionDialog; 1180 Color: TColor); 1181var 1182 SelectionColor: TGDKColor; 1183 colorSel: PGtkColorSelection; 1184begin 1185 Color := TColor(ColorToRGB(Color)); 1186 SelectionColor := TColortoTGDKColor(Color); 1187 colorSel := PGtkColorSelection(ColorSelection^.colorsel); 1188 gtk_color_selection_set_current_color(colorSel, @SelectionColor); 1189 gtk_color_selection_set_previous_color(colorSel, @SelectionColor); 1190end; 1191 1192class procedure TGtk2WSCommonDialog.SetColorDialogPalette( 1193 ColorSelection: PGtkColorSelectionDialog; Palette: TStrings); 1194const 1195 PaletteSetting = 'gtk-color-palette'; 1196var 1197 colorSel: PGtkColorSelection; 1198 settings: PGtkSettings; 1199 new_palette: Pgchar; 1200 colors: PGdkColor; 1201 colors_len: gint; 1202 1203 procedure FillCustomColors; 1204 var 1205 i, AIndex: integer; 1206 AColor: TColor; 1207 begin 1208 for i := 0 to Palette.Count - 1 do 1209 if ExtractColorIndexAndColor(Palette, i, AIndex, AColor) then 1210 if AIndex < colors_len then 1211 colors[AIndex] := TColortoTGDKColor(AColor); 1212 end; 1213 1214begin 1215 colorSel := PGtkColorSelection(ColorSelection^.colorsel); 1216 // show palette 1217 gtk_color_selection_set_has_palette(colorSel, True); 1218 1219 // replace palette. it is stored in 'gtk-color-palette' settings. 1220 // 1. get original palette => we will know colors and replace only part of it 1221 settings := gtk_widget_get_settings(PGtkWidget(colorSel)); 1222 new_palette := nil; 1223 g_object_get(settings, PaletteSetting, [@new_palette, nil]); 1224 colors:=nil; 1225 gtk_color_selection_palette_from_string(new_palette, colors, @colors_len); 1226 g_free(new_palette); 1227 1228 // 2. fill original palette with our custom colors 1229 FillCustomColors; 1230 1231 // 3. set new palette back to settings 1232 new_palette := gtk_color_selection_palette_to_string(colors, colors_len); 1233 g_free(colors); 1234 gtk_settings_set_string_property(settings, PaletteSetting, new_palette, 'gtk_color_selection_palette_to_string'); 1235 g_free(new_palette); 1236end; 1237 1238class procedure TGtk2WSCommonDialog.SetCallbacks(const AGtkWidget: PGtkWidget; 1239 const AWidgetInfo: PWidgetInfo); 1240begin 1241 g_signal_connect(PGtkObject(AGtkWidget), 1242 'destroy', gtk_Signal_Func(@gtkDialogDestroyCB), AWidgetInfo^.LCLObject); 1243 g_signal_connect(PGtkObject(AGtkWidget), 1244 'delete-event', gtk_Signal_Func(@gtkDialogCloseQueryCB), AWidgetInfo^.LCLObject); 1245 g_signal_connect(PGtkObject(AGtkWidget), 1246 'key-press-event', gtk_Signal_Func(@GTKDialogKeyUpDownCB), AWidgetInfo^.LCLObject); 1247 g_signal_connect(PGtkObject(AGtkWidget), 1248 'key-release-event', gtk_Signal_Func(@GTKDialogKeyUpDownCB), AWidgetInfo^.LCLObject); 1249 g_signal_connect(PGtkObject(AGtkWidget), 1250 'realize', gtk_Signal_Func(@GTKDialogRealizeCB), AWidgetInfo^.LCLObject); 1251end; 1252 1253class procedure TGtk2WSCommonDialog.SetSizes(const AGtkWidget: PGtkWidget; 1254 const AWidgetInfo: PWidgetInfo); 1255var 1256 NewWidth, NewHeight: integer; 1257begin 1258 // set default size 1259 NewWidth := TCommonDialog(AWidgetInfo^.LCLObject).Width; 1260 if NewWidth <= 0 then 1261 NewWidth := -2; // -2 = let the window manager decide 1262 NewHeight := TCommonDialog(AWidgetInfo^.LCLObject).Height; 1263 if NewHeight<=0 then 1264 NewHeight := -2; // -2 = let the window manager decide 1265 if (NewWidth > 0) or (NewHeight > 0) then 1266 gtk_window_set_default_size(PGtkWindow(AGtkWidget), NewWidth, NewHeight); 1267end; 1268 1269class function TGtk2WSCommonDialog.CreateHandle( 1270 const ACommonDialog: TCommonDialog): THandle; 1271begin 1272 Result := 0; 1273end; 1274 1275class procedure TGtk2WSCommonDialog.ShowModal(const ACommonDialog: TCommonDialog); 1276var 1277 GtkWindow: PGtkWindow; 1278begin 1279 ReleaseMouseCapture; 1280 GtkWindow:={%H-}PGtkWindow(ACommonDialog.Handle); 1281 gtk_window_set_title(GtkWindow,PChar(ACommonDialog.Title)); 1282 if ACommonDialog is TColorDialog then 1283 begin 1284 SetColorDialogColor(PGtkColorSelectionDialog(GtkWindow), 1285 TColorDialog(ACommonDialog).Color); 1286 SetColorDialogPalette(PGtkColorSelectionDialog(GtkWindow), 1287 TColorDialog(ACommonDialog).CustomColors); 1288 end; 1289 1290 gtk_window_set_position(GtkWindow, GTK_WIN_POS_CENTER); 1291 GtkWindowShowModal(nil, GtkWindow); 1292end; 1293 1294class procedure TGtk2WSCommonDialog.DestroyHandle( 1295 const ACommonDialog: TCommonDialog); 1296begin 1297 { TODO: cleanup } 1298 TGtk2WidgetSet(WidgetSet).DestroyLCLComponent(ACommonDialog); 1299end; 1300 1301{ TGtk2WSColorDialog } 1302 1303class procedure TGtk2WSColorDialog.SetCallbacks(const AGtkWidget: PGtkWidget; 1304 const AWidgetInfo: PWidgetInfo); 1305begin 1306 TGtk2WSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo); 1307 g_signal_connect(PGtkObject(PGtkColorSelectionDialog(AGtkWidget)^.ok_button), 1308 'clicked', gtk_signal_func(@gtkDialogOKclickedCB), AWidgetInfo^.LCLObject); 1309 g_signal_connect(PGtkObject(PGtkColorSelectionDialog(AGtkWidget)^.cancel_button), 1310 'clicked', gtk_signal_func(@gtkDialogCancelclickedCB), AWidgetInfo^.LCLObject); 1311end; 1312 1313class function TGtk2WSColorDialog.CreateHandle( 1314 const ACommonDialog: TCommonDialog): THandle; 1315var 1316 Widget: PGtkWidget; 1317 WidgetInfo: PWidgetInfo; 1318begin 1319 Widget := gtk_color_selection_dialog_new(PChar(ACommonDialog.Title)); 1320 1321 Result := THandle({%H-}PtrUInt(Widget)); 1322 WidgetInfo := CreateWidgetInfo(Widget); 1323 WidgetInfo^.LCLObject := ACommonDialog; 1324 TGtk2WSCommonDialog.SetSizes(Widget, WidgetInfo); 1325 SetCallbacks(Widget, WidgetInfo); 1326end; 1327 1328class function TGtk2WSColorDialog.QueryWSEventCapabilities( 1329 const ACommonDialog: TCommonDialog): TCDWSEventCapabilities; 1330begin 1331 Result := [cdecWSPerformsDoShow]; 1332end; 1333 1334{ TGtk2WSFontDialog } 1335 1336class procedure TGtk2WSFontDialog.SetCallbacks(const AGtkWidget: PGtkWidget; 1337 const AWidgetInfo: PWidgetInfo); 1338begin 1339 TGtk2WSCommonDialog.SetCallbacks(AGtkWidget, AWidgetInfo); 1340 // connect Ok, Cancel and Apply Button 1341 g_signal_connect( 1342 PGtkObject(PGtkFontSelectionDialog(AGtkWidget)^.ok_button), 1343 'clicked', gtk_signal_func(@gtkDialogOKclickedCB), AWidgetInfo^.LCLObject); 1344 g_signal_connect( 1345 PGtkObject(PGtkFontSelectionDialog(AGtkWidget)^.cancel_button), 1346 'clicked', gtk_signal_func(@gtkDialogCancelclickedCB), AWidgetInfo^.LCLObject); 1347 g_signal_connect( 1348 PGtkObject(PGtkFontSelectionDialog(AGtkWidget)^.apply_button), 1349 'clicked', gtk_signal_func(@gtkDialogApplyclickedCB), AWidgetInfo^.LCLObject); 1350end; 1351 1352class function TGtk2WSFontDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle; 1353var 1354 FontDesc: PPangoFontDescription; 1355 TmpStr: pChar; 1356 1357 Widget: PGtkWidget; 1358 WidgetInfo: PWidgetInfo; 1359 FontDialog: TFontDialog absolute ACommonDialog; 1360begin 1361 Widget := gtk_font_selection_dialog_new(PChar(ACommonDialog.Title)); 1362 1363 if fdApplyButton in FontDialog.Options then 1364 gtk_widget_show(PGtkFontSelectionDialog(Widget)^.apply_button); 1365 // set preview text 1366 if FontDialog.PreviewText <> '' then 1367 gtk_font_selection_dialog_set_preview_text(PGtkFontSelectionDialog(Widget), 1368 PChar(FontDialog.PreviewText)); 1369 1370 // set font name in XLFD format 1371 if IsFontNameXLogicalFontDesc(FontDialog.Font.Name) then 1372 gtk_font_selection_dialog_set_font_name(PGtkFontSelectionDialog(Widget), 1373 PChar(FontDialog.Font.Name)) 1374 else 1375 begin 1376 FontDesc := pango_font_description_new; 1377 with FontDialog.Font do 1378 begin 1379 pango_font_description_set_size(FontDesc, Size * PANGO_SCALE); 1380 1381 if fsBold in Style then 1382 pango_font_description_set_weight(FontDesc, PANGO_WEIGHT_BOLD) 1383 else 1384 pango_font_description_set_weight(FontDesc, PANGO_WEIGHT_NORMAL); 1385 1386 if fsItalic in Style then 1387 pango_font_description_set_style(FontDesc, PANGO_STYLE_ITALIC) 1388 else 1389 pango_font_description_set_style(FontDesc, PANGO_STYLE_NORMAL); 1390 1391 pango_font_description_set_family(FontDesc, PChar(Name)); 1392 end; 1393 TmpStr := pango_font_description_to_string(FontDesc); 1394 gtk_font_selection_dialog_set_font_name(PGtkFontSelectionDialog(Widget), TmpStr); 1395 g_free(TmpStr); 1396 pango_font_description_free(FontDesc); 1397 end; 1398 1399 { This functionality does not seem to be available in GTK2 } 1400 // Honor selected TFontDialogOption flags 1401 1402 Result := THandle({%H-}PtrUInt(Widget)); 1403 WidgetInfo := CreateWidgetInfo(Widget); 1404 WidgetInfo^.LCLObject := ACommonDialog; 1405 TGtk2WSCommonDialog.SetSizes(Widget, WidgetInfo); 1406 SetCallbacks(Widget, WidgetInfo); 1407end; 1408 1409class function TGtk2WSFontDialog.QueryWSEventCapabilities( 1410 const ACommonDialog: TCommonDialog): TCDWSEventCapabilities; 1411begin 1412 Result := [cdecWSPerformsDoShow]; 1413end; 1414 1415end. 1416