unit ugtkimage;

{$mode objfpc}{$H+}

interface

uses
  Graphics, Buttons,
  GtkDef,
  gtk2,
  GTK2Int,
  gdk2pixbuf,
  gdk2,
  glib2,
  InterfaceBase;

const
  GTK_STOCK_DIALOG_INFO = gtk2.GTK_STOCK_DIALOG_INFO;
  GTK_STOCK_DIALOG_WARNING = gtk2.GTK_STOCK_DIALOG_WARNING;
  GTK_STOCK_DIALOG_ERROR = gtk2.GTK_STOCK_DIALOG_ERROR;
  GTK_STOCK_DIALOG_QUESTION = gtk2.GTK_STOCK_DIALOG_QUESTION;
  GTK_STOCK_DND = gtk2.GTK_STOCK_DND;
  GTK_STOCK_DND_MULTIPLE = gtk2.GTK_STOCK_DND_MULTIPLE;
    GTK_STOCK_ABOUT = gtk2.GTK_STOCK_ABOUT;
  GTK_STOCK_ADD_name = gtk2.GTK_STOCK_ADD_name;
  GTK_STOCK_APPLY = gtk2.GTK_STOCK_APPLY;
  GTK_STOCK_BOLD = gtk2.GTK_STOCK_BOLD;
  GTK_STOCK_CANCEL = gtk2.GTK_STOCK_CANCEL;
  GTK_STOCK_CDROM = gtk2.GTK_STOCK_CDROM;
  GTK_STOCK_CLEAR = gtk2.GTK_STOCK_CLEAR;
  GTK_STOCK_CLOSE = gtk2.GTK_STOCK_CLOSE;
    GTK_STOCK_COLOR_PICKER = gtk2.GTK_STOCK_COLOR_PICKER;
  GTK_STOCK_CONVERT = gtk2.GTK_STOCK_CONVERT;
    GTK_STOCK_CONNECT = gtk2.GTK_STOCK_CONNECT;
  GTK_STOCK_COPY = gtk2.GTK_STOCK_COPY;
  GTK_STOCK_CUT = gtk2.GTK_STOCK_CUT;
  GTK_STOCK_DELETE = gtk2.GTK_STOCK_DELETE;
  GTK_STOCK_EXECUTE = gtk2.GTK_STOCK_EXECUTE;
  GTK_STOCK_FIND = gtk2.GTK_STOCK_FIND;
  GTK_STOCK_FIND_AND_REPLACE = gtk2.GTK_STOCK_FIND_AND_REPLACE;
  GTK_STOCK_FLOPPY = gtk2.GTK_STOCK_FLOPPY;
  GTK_STOCK_GOTO_BOTTOM = gtk2.GTK_STOCK_GOTO_BOTTOM;
  GTK_STOCK_GOTO_FIRST = gtk2.GTK_STOCK_GOTO_FIRST;
  GTK_STOCK_GOTO_LAST = gtk2.GTK_STOCK_GOTO_LAST;
  GTK_STOCK_GOTO_TOP = gtk2.GTK_STOCK_GOTO_TOP;
  GTK_STOCK_GO_BACK = gtk2.GTK_STOCK_GO_BACK;
  GTK_STOCK_GO_DOWN = gtk2.GTK_STOCK_GO_DOWN;
  GTK_STOCK_GO_FORWARD = gtk2.GTK_STOCK_GO_FORWARD;
  GTK_STOCK_GO_UP = gtk2.GTK_STOCK_GO_UP;
  GTK_STOCK_HELP = gtk2.GTK_STOCK_HELP;
  GTK_STOCK_HOME = gtk2.GTK_STOCK_HOME;
  GTK_STOCK_INDEX = gtk2.GTK_STOCK_INDEX;
  GTK_STOCK_ITALIC = gtk2.GTK_STOCK_ITALIC;
  GTK_STOCK_JUMP_TO = gtk2.GTK_STOCK_JUMP_TO;
  GTK_STOCK_JUSTIFY_CENTER = gtk2.GTK_STOCK_JUSTIFY_CENTER;
  GTK_STOCK_JUSTIFY_FILL = gtk2.GTK_STOCK_JUSTIFY_FILL;
  GTK_STOCK_JUSTIFY_LEFT = gtk2.GTK_STOCK_JUSTIFY_LEFT;
  GTK_STOCK_JUSTIFY_RIGHT = gtk2.GTK_STOCK_JUSTIFY_RIGHT;
    GTK_STOCK_MEDIA_FORWARD = gtk2.GTK_STOCK_MEDIA_FORWARD;
    GTK_STOCK_MEDIA_NEXT = gtk2.GTK_STOCK_MEDIA_NEXT;
    GTK_STOCK_MEDIA_PAUSE = gtk2.GTK_STOCK_MEDIA_PAUSE;
    GTK_STOCK_MEDIA_PLAY = gtk2.GTK_STOCK_MEDIA_PLAY;
    GTK_STOCK_MEDIA_PREVIOUS = gtk2.GTK_STOCK_MEDIA_PREVIOUS;
    GTK_STOCK_MEDIA_RECORD = gtk2.GTK_STOCK_MEDIA_RECORD;
    GTK_STOCK_MEDIA_REWIND = gtk2.GTK_STOCK_MEDIA_REWIND;
    GTK_STOCK_MEDIA_STOP = gtk2.GTK_STOCK_MEDIA_STOP;
  GTK_STOCK_MISSING_IMAGE = gtk2.GTK_STOCK_MISSING_IMAGE;
  GTK_STOCK_NEW = gtk2.GTK_STOCK_NEW;
  GTK_STOCK_NO = gtk2.GTK_STOCK_NO;
  GTK_STOCK_OK = gtk2.GTK_STOCK_OK;
  GTK_STOCK_OPEN = gtk2.GTK_STOCK_OPEN;
  GTK_STOCK_PASTE = gtk2.GTK_STOCK_PASTE;
  GTK_STOCK_PREFERENCES = gtk2.GTK_STOCK_PREFERENCES;
  GTK_STOCK_PRINT = gtk2.GTK_STOCK_PRINT;
  GTK_STOCK_PRINT_PREVIEW = gtk2.GTK_STOCK_PRINT_PREVIEW;
  GTK_STOCK_PROPERTIES = gtk2.GTK_STOCK_PROPERTIES;
  GTK_STOCK_QUIT = gtk2.GTK_STOCK_QUIT;
  GTK_STOCK_REDO = gtk2.GTK_STOCK_REDO;
  GTK_STOCK_REFRESH = gtk2.GTK_STOCK_REFRESH;
  GTK_STOCK_REMOVE = gtk2.GTK_STOCK_REMOVE;
  GTK_STOCK_REVERT_TO_SAVED = gtk2.GTK_STOCK_REVERT_TO_SAVED;
  GTK_STOCK_SAVE = gtk2.GTK_STOCK_SAVE;
  GTK_STOCK_SAVE_AS = gtk2.GTK_STOCK_SAVE_AS;
  GTK_STOCK_SELECT_COLOR = gtk2.GTK_STOCK_SELECT_COLOR;
  GTK_STOCK_SELECT_FONT = gtk2.GTK_STOCK_SELECT_FONT;
  GTK_STOCK_SORT_ASCENDING = gtk2.GTK_STOCK_SORT_ASCENDING;
  GTK_STOCK_SORT_DESCENDING = gtk2.GTK_STOCK_SORT_DESCENDING;
  GTK_STOCK_SPELL_CHECK = gtk2.GTK_STOCK_SPELL_CHECK;
  GTK_STOCK_STOP = gtk2.GTK_STOCK_STOP;
  GTK_STOCK_STRIKETHROUGH = gtk2.GTK_STOCK_STRIKETHROUGH;
  GTK_STOCK_UNDELETE = gtk2.GTK_STOCK_UNDELETE;
  GTK_STOCK_UNDERLINE = gtk2.GTK_STOCK_UNDERLINE;
  GTK_STOCK_UNDO = gtk2.GTK_STOCK_UNDO;
  GTK_STOCK_YES = gtk2.GTK_STOCK_YES;
  GTK_STOCK_ZOOM_100 = gtk2.GTK_STOCK_ZOOM_100;
  GTK_STOCK_ZOOM_FIT = gtk2.GTK_STOCK_ZOOM_FIT;
  GTK_STOCK_ZOOM_IN = gtk2.GTK_STOCK_ZOOM_IN;
  GTK_STOCK_ZOOM_OUT = gtk2.GTK_STOCK_ZOOM_OUT;

const
  SIZE_INVALID       = 24;
  SIZE_MENU          = 16;
  SIZE_SMALL_TOOLBAR = 22;
  SIZE_LARGE_TOOLBAR = 24;
  SIZE_DIALOG        = 48;
  SIZE_DND           = 32;
  SIZE_BUTTON        = 20;

type
  { TIconMaster }

  TIconMaster = class(TObject)
  private
    fDefaultSize: gint;
    ftheme: PGtkIconTheme;
    constructor Create;
    destructor Destroy; override;
  public
    function LookupIcon(const Name: String; Size: gint;
      Target: TCustomBitmap): Boolean; overload;
    function LookupIcon(const Name: String; Target: TCustomBitmap
      ): Boolean; overload; inline;
    function LookupButton(const Name: String; Target: TCustomBitBtn
      ): Boolean; overload; inline;
    function LookupButton(const Name: String; Target: TCustomSpeedButton
      ): Boolean; overload; inline;
    function LookupDialog(const Name: String; Target: TCustomBitmap
      ): Boolean; inline;
    property DefaultSize: gint read fDefaultSize write fDefaultSize default
      SIZE_INVALID;
  end;

var
  IconMaster: TIconMaster = nil;

implementation

{ TIconMaster }

constructor TIconMaster.Create;
begin
  ftheme := gtk_icon_theme_get_default;
end;

destructor TIconMaster.Destroy;
begin
  inherited Destroy;
end;

function TIconMaster.LookupIcon(const Name: String; Size: gint;
  Target: TCustomBitmap): Boolean;
var
  pixbuf: PGdkPixbuf;
  pixmap: PGDIObject;
begin
  Result := False;

  pixbuf := gtk_icon_theme_load_icon (ftheme,
                                   PChar(Name), (* icon name *)
                                   Size, (* size *)
                                   (* mit FORCE_SVG gibt es eindeutig beswere
                                      Ergebnisse, da das Icon nicht vergrößert
                                      werden muss *)
                                   GTK_ICON_LOOKUP_FORCE_SVG,  (* flags *)
                                   nil);
  if pixbuf <> nil then
  begin
    try
      pixmap := TGTK2WidgetSet(WidgetSet).NewGDIObject(gdiBitmap);
      (* aus TGTK2WidgetSet.LoadStockPixmap *)
      with pixmap^ do
      begin
        GDIBitmapType := gbPixmap;
        visual := gdk_visual_get_system();
        gdk_visual_ref(visual);
        colormap := gdk_colormap_get_system();
        gdk_colormap_ref(colormap);
        gdk_pixbuf_render_pixmap_and_mask(pixbuf, GDIPixmapObject.Image,
          GDIPixmapObject.Mask, 128);
      end;

      Target.MaskHandle := 0;
      Target.Handle := PtrUInt(pixmap);
      Result := True;
    finally;
      g_object_unref (pixbuf);
    end;
  end;
end;

function TIconMaster.LookupIcon(const Name: String; Target: TCustomBitmap
  ): Boolean; inline;
begin
  Result := LookupIcon(Name, DefaultSize, Target);
end;

function TIconMaster.LookupButton(const Name: String; Target: TCustomBitBtn
  ): Boolean; inline;
begin
  Result := LookupIcon(Name, SIZE_BUTTON, Target.Glyph);
end;

function TIconMaster.LookupButton(const Name: String; Target: TCustomSpeedButton
  ): Boolean; inline;
begin
  Result := LookupIcon(Name, SIZE_BUTTON, Target.Glyph);
end;

function TIconMaster.LookupDialog(const Name: String; Target: TCustomBitmap
  ): Boolean; inline;
begin
  Result := LookupIcon(Name, SIZE_DIALOG, Target);
end;

initialization
  IconMaster := TIconMaster.Create;
finalization
// benötig nicht die unit SysUtils für FreeAndNil
  if IconMaster <> nil then
  begin
    IconMaster.Destroy;
    IconMaster := nil;
  end;
end.

