{****************************************************************************** TGtk2WidgetSet ****************************************************************************** ***************************************************************************** * * * This file is part of the Lazarus Component Library (LCL) * * * * See the file COPYING.LCL, 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. * * * ***************************************************************************** } {$IFOPT C-} // Uncomment for local trace // {$C+} // {$DEFINE ASSERT_IS_ON} {$ENDIF} function GTK2FocusCB( widget: PGtkWidget; event:PGdkEventFocus; data: gPointer) : GBoolean; cdecl; var Status : gBoolean; begin Status := GTKFocusCB(Widget, Event, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; function GTK2FocusCBAfter(widget: PGtkWidget; event:PGdkEventFocus; data: gPointer) : GBoolean; cdecl; var Status : gBoolean; begin Status := GTKFocusCBAfter(Widget, Event, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; function gtk2HideCB( widget: PGtkWidget; data: gPointer) : GBoolean; cdecl; var Status : GBoolean; begin Status := gtkHideCB(Widget, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; function GTK2KeyUpDown(Widget: PGtkWidget; Event : pgdkeventkey; Data: gPointer) : GBoolean; cdecl; var Status : gBoolean; begin Status := GTKKeyUpDown(Widget, Event, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; function GTK2KillFocusCB(widget: PGtkWidget; event:PGdkEventFocus; data: gPointer) : GBoolean; cdecl; var Status : gBoolean; begin Status := GTKKillFocusCB(Widget, Event, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; function GTK2KillFocusCBAfter(widget: PGtkWidget; event:PGdkEventFocus; data: gPointer) : GBoolean; cdecl; var Status : gBoolean; begin Status := GTKKillFocusCBAfter(Widget, Event, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; function gtk2showCB( widget: PGtkWidget; data: gPointer) : GBoolean; cdecl; var Status : GBoolean; begin Status := gtkshowCB(Widget, Data); if GtkWidgetIsA(Widget,GTK_APIWIDGETCLIENT_TYPE) then Result := Status else Result := False; end; Procedure gtk_clb_toggle(cellrenderertoggle : PGtkCellRendererToggle; arg1 : PGChar; WinControl: TWinControl); cdecl; var aWidget : PGTKWidget; aTreeModel : PGtkTreeModel; aTreeIter : TGtkTreeIter; value : pgValue; begin aWidget := GetWidgetInfo(Pointer(WinControl.Handle), True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model (GTK_TREE_VIEW(aWidget)); if (gtk_tree_model_get_iter_from_string (aTreeModel, @aTreeIter, arg1)) then begin aTreeIter.stamp := GTK_LIST_STORE (aTreeModel)^.stamp; //strange hack value := g_new0(SizeOf(TgValue), 1); gtk_tree_model_get_value(aTreeModel, @aTreeIter, 0, value); g_value_set_boolean(value, not g_value_get_boolean(value)); gtk_list_store_set_value (GTK_LIST_STORE (aTreeModel), @aTreeIter, 0, value); g_value_unset(value); g_free(value); end; end; Procedure gtk_clb_toggle_row_activated(treeview : PGtkTreeView; arg1 : PGtkTreePath; arg2 : PGtkTreeViewColumn; data : gpointer); cdecl; var aTreeModel : PGtkTreeModel; aTreeIter : TGtkTreeIter; value : PGValue; begin aTreeModel := gtk_tree_view_get_model (treeview); if (gtk_tree_model_get_iter (aTreeModel, @aTreeIter, arg1)) then begin aTreeIter.stamp := GTK_LIST_STORE (aTreeModel)^.stamp; //strange hack value := g_new0(SizeOf(TgValue), 1); gtk_tree_model_get_value(aTreeModel, @aTreeIter, 0, value); g_value_set_boolean(value, not g_value_get_boolean(value)); gtk_list_store_set_value (GTK_LIST_STORE (aTreeModel), @aTreeIter, 0, value); g_value_unset(value); g_free(value); end; end; {$IfNDef GTK2_2} Procedure gtkTreeSelectionCountSelectedRows(model : PGtkTreeModel; path : PGtkTreePath; iter : PGtkTreeIter; data : PGint); cdecl; begin If Assigned(Data) then Inc(Data^); end; Type PPGList = ^PGList; Procedure gtkTreeSelectionGetSelectedRows(model : PGtkTreeModel; path : PGtkTreePath; iter : PGtkTreeIter; data : PPGList); cdecl; begin If Assigned(Data) then Data^ := g_list_append(Data^, gtk_tree_path_copy(path)); end; {$EndIf} {------------------------------------------------------------------------------ procedure TGtk2WidgetSet.AppendText(Sender: TObject; Str: PChar); ------------------------------------------------------------------------------} procedure TGtk2WidgetSet.AppendText(Sender: TObject; Str: PChar); var Widget : PGtkWidget; aTextBuffer : PGtkTextBuffer; aTextIter1 : TGtkTextIter; aTextIter2 : TGtkTextIter; begin if Str=nil then exit; if (Sender is TWinControl) then begin case TWinControl(Sender).fCompStyle of csMemo: begin Widget:= GetWidgetInfo(Pointer(TWinControl(Sender).Handle), True)^.CoreWidget; aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); gtk_text_buffer_begin_user_action(aTextBuffer); gtk_text_buffer_get_bounds(aTextBuffer, @aTextIter1, @aTextIter2); gtk_text_buffer_insert(aTextBuffer, @aTextIter2, str, StrLen(str)); gtk_text_buffer_end_user_action(aTextBuffer); end; else inherited AppendText(Sender, Str); end; end; end; function TGtk2WidgetSet.CreateComponent(Sender : TObject): THandle; var Caption : ansistring; // the caption of "Sender" StrTemp : PChar; // same as "caption" but as PChar TempWidget, TempWidget2 : PGTKWidget; // pointer to gtk-widget (local use when neccessary) p : pointer; // ptr to the newly created GtkWidget CompStyle, // componentstyle (type) of GtkWidget which will be created TempInt : Integer; // local use when neccessary // - for csBitBtn Box : Pointer; // currently only used for TBitBtn pixmapwid : pGtkWidget; // currently only used for TBitBtn label1 : pgtkwidget; // currently only used for TBitBtn ParentForm: TCustomForm; AccelText : PChar; AccelKey : guint; SetupProps : boolean; AWindow: PGdkWindow; liststore : PGtkListStore; renderer : PGtkCellRenderer; column : PGtkTreeViewColumn; begin p := nil; SetupProps:= false; CompStyle := GetCompStyle(Sender); Caption := GetCaption(Sender); strTemp := StrAlloc(length(Caption) + 1); StrPCopy(strTemp, Caption); case CompStyle of csEdit : begin p := gtk_entry_new(); gtk_editable_set_editable (PGtkEditable(P), not TCustomEdit(Sender).ReadOnly); gtk_widget_show_all(P); end; csListBox, csCheckListBox: begin p:= gtk_scrolled_window_new(nil, nil); GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.hscrollbar, GTK_CAN_FOCUS); GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.vscrollbar, GTK_CAN_FOCUS); gtk_scrolled_window_set_policy(PGtkScrolledWindow(p), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_show(p); if (CompStyle = csListBox) then liststore := gtk_list_store_new (1, [G_TYPE_STRING, nil]) else liststore := gtk_list_store_new (2, [G_TYPE_BOOLEAN, G_TYPE_STRING, nil]); TempWidget:= gtk_tree_view_new_with_model (GTK_TREE_MODEL (liststore)); g_object_unref (G_OBJECT (liststore)); TempInt := 0; if (CompStyle = csCheckListBox) then begin renderer := gtk_cell_renderer_toggle_new(); column := gtk_tree_view_column_new_with_attributes('', renderer, ['active', 0, nil]); gtk_cell_renderer_toggle_set_active(GTK_CELL_RENDERER_TOGGLE(renderer), True); gtk_tree_view_append_column (GTK_TREE_VIEW (TempWidget), column); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); g_signal_connect (renderer, 'toggled', G_CALLBACK (@gtk_clb_toggle), Sender); g_signal_connect (TempWidget, 'row_activated', G_CALLBACK (@gtk_clb_toggle_row_activated), Sender); TempInt := 1; end; renderer := gtk_cell_renderer_text_new(); column := gtk_tree_view_column_new_with_attributes ('LISTITEMS', renderer, ['text', TempInt, nil]); gtk_tree_view_append_column (GTK_TREE_VIEW (TempWidget), column); gtk_tree_view_column_set_clickable (GTK_TREE_VIEW_COLUMN (column), TRUE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW (TempWidget), False); gtk_container_add(GTK_CONTAINER(p), TempWidget); gtk_widget_show(TempWidget); SetMainWidget(p, TempWidget); GetWidgetInfo(p, True)^.CoreWidget := TempWidget; if Sender is TCustomListBox then SetSelectionMode(Sender,p,TCustomListBox(Sender).MultiSelect, TCustomListBox(Sender).ExtendedSelect); end; csMemo : begin P := gtk_scrolled_window_new(nil, nil); TempWidget := gtk_text_view_new(); gtk_container_add(p, TempWidget); GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.hscrollbar, GTK_CAN_FOCUS); GTK_WIDGET_UNSET_FLAGS(PGtkScrolledWindow(p)^.vscrollbar, GTK_CAN_FOCUS); gtk_scrolled_window_set_policy(PGtkScrolledWindow(p), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_set_shadow_type(PGtkScrolledWindow(p),GTK_SHADOW_IN); SetMainWidget(p, TempWidget); GetWidgetInfo(p, True)^.CoreWidget := TempWidget; gtk_text_view_set_editable (PGtkTextView(TempWidget), not TCustomMemo(Sender).ReadOnly); if TCustomMemo(Sender).WordWrap then gtk_text_view_set_wrap_mode(PGtkTextView(TempWidget), GTK_WRAP_WORD) else gtk_text_view_set_wrap_mode(PGtkTextView(TempWidget), GTK_WRAP_NONE); gtk_widget_show_all(P); SetupProps:= true; end; else begin StrDispose(StrTemp); Result:=Inherited CreateComponent(Sender); Exit; end; end; //end case StrDispose(StrTemp); FinishComponentCreate(Sender, P, SetupProps); Result := THandle(P); end; function TGtk2WidgetSet.GetText(Sender: TComponent; var Text: String): Boolean; var CS: PChar; Widget : PGtkWidget; aTextBuffer : PGtkTextBuffer; aTextIter1 : TGtkTextIter; aTextIter2 : TGtkTextIter; begin Result := True; case TControl(Sender).fCompStyle of csEdit: begin Widget:= GTK_WIDGET(Pointer(TWinControl(Sender).Handle)); CS := gtk_editable_get_chars(GTK_EDITABLE(Widget), 0, -1); Text := StrPas(CS); g_free(CS); end; csMemo : begin Widget:= GetWidgetInfo(Pointer(TWinControl(Sender).Handle), True)^.CoreWidget; aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); gtk_text_buffer_get_bounds(aTextBuffer, @aTextIter1, @aTextIter2); CS := gtk_text_buffer_get_text(aTextBuffer, @aTextIter1, @aTextIter2, True); Text := StrPas(CS); g_free(CS); end; else Result := inherited GetText(Sender, Text); end; end; procedure Tgtk2widgetset.HookSignals(const AGTKObject: PGTKObject; const ALCLObject: TObject); begin if (ALCLObject is TWinControl) then Begin inherited HookSignals(AGTKObject,ALCLObject); End; if (ALCLObject is TControl) then Begin case TControl(ALCLObject).FCompStyle of csEdit: begin SetCallback(LM_CHANGED, AGTKObject, ALCLObject); SetCallback(LM_ACTIVATE, AGTKObject,ALCLObject); SetCallback(LM_CUTTOCLIP, AGTKObject,ALCLObject); SetCallback(LM_COPYTOCLIP, AGTKObject,ALCLObject); SetCallback(LM_PASTEFROMCLIP, AGTKObject,ALCLObject); end; csMemo: begin // SetCallback(LM_CHANGED, AGTKObject,ALCLObject); //SetCallback(LM_ACTIVATE, AGTKObject,ALCLObject); SetCallback(LM_CUTTOCLIP, AGTKObject,ALCLObject); SetCallback(LM_COPYTOCLIP, AGTKObject,ALCLObject); SetCallback(LM_PASTEFROMCLIP, AGTKObject,ALCLObject); //SetCallback(LM_INSERTTEXT, AGTKObject,ALCLObject); end; end; //case end else If (ALCLObject is TMenuItem) then Begin SetCallback(LM_ACTIVATE,AGTKObject,ALCLObject); end; end; {------------------------------------------------------------------------------ Method: TGtk2WidgetSet.IntSendMessage3 Params: LM_Message - message to be processed by GTK2 Sender - sending control data - pointer to (optional) Returns: depends on the message and the sender Processes messages from different components. WARNING: the result of this function sometimes is not always really an integer!!!!! ------------------------------------------------------------------------------} function TGtk2WidgetSet.IntSendMessage3(LM_Message : Integer; Sender : TObject; data : pointer) : integer; var handle : hwnd; // handle of sender pStr : PChar; // temporary string pointer, must be allocated/disposed when used! Widget : PGtkWidget; // pointer to gtk-widget (local use when neccessary) ChildWidget : PGtkWidget; // generic pointer to a child gtk-widget (local use when neccessary) aTextIter1 : TGtkTextIter; aTextIter2 : TGtkTextIter; aTextBuffer : PGtkTextBuffer; aTreeSelect : PGtkTreeSelection; aTreeModel : PGtkTreeModel; aTreeIter : TGtkTreeIter; aTreePath : PGtkTreePath; TempInt : Integer; TempBool : Boolean; list : pGList; begin Result := 0; //default value just in case nothing sets it Assert(False, 'Trace:Message received'); if Sender <> nil then Assert(False, Format('Trace: [TGtk2WidgetSet.IntSendMessage3] %s --> Sent LM_Message: $%x (%s); Data: %d', [Sender.ClassName, LM_Message, GetMessageName(LM_Message), Integer(data)])); // The following case is now split into 2 separate parts: // 1st part should contain all messages which don't need the "handle" variable // 2nd part has to contain all parts which need the handle // Reason for this split are performance issues since we need RTTI to // retrieve the handle { case LM_Message of else} begin handle := hwnd(ObjectToGtkObject(Sender)); Case LM_Message of LM_CLB_GETCHECKED : begin Result := 0; if Assigned(Data) and (Sender is TControl) and (TControl(Sender).fCompStyle = csCheckListBox) then begin { Get the child in question of that index } Widget := GetWidgetInfo(Pointer(Handle),True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model(GTK_TREE_VIEW(Widget)); if (aTreeModel <> nil) and (gtk_tree_model_iter_nth_child(aTreeModel,@aTreeIter, nil, Integer(Data^))) then begin gtk_tree_model_get (aTreeModel, @aTreeIter, [0, @TempBool, -1]); if TempBool then result := 1; end; end; end; LM_CLB_SETCHECKED : begin if Assigned(Data) and (Sender is TControl) and (TControl(Sender).fCompStyle = csCheckListBox) then begin { Get the child in question of that index } Widget := GetWidgetInfo(Pointer(Handle),True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model(GTK_TREE_VIEW(Widget)); if (aTreeModel <> nil) and (gtk_tree_model_iter_nth_child(aTreeModel,@aTreeIter, nil, Integer(Data^))) then gtk_list_store_set(GTK_LIST_STORE(aTreeModel), @aTreeIter, [0, TLMSetChecked(Data^).Checked, -1]); end; end; LM_GETITEMINDEX : begin case TControl(Sender).fCompStyle of csListBox, csCheckListBox: begin if Handle<>0 then begin Result:= -1; Widget := GetWidgetInfo(Pointer(Handle),True)^.CoreWidget; aTreeSelect := gtk_tree_view_get_selection(GTK_TREE_VIEW(Widget)); {$IfNDef GTK2_2} list := nil; gtk_tree_selection_selected_foreach(aTreeSelect, TGtkTreeSelectionForeachFunc(@gtkTreeSelectionGetSelectedRows), @List); {$Else} list := gtk_tree_selection_get_selected_rows(aTreeSelect, aTreeModel); {$EndIf} if not Assigned(List) then begin result := -1; exit; end; List := g_list_last(List); aTreePath := PGtkTreePath(List^.Data); Result := gtk_tree_path_get_indices(aTreePath)[0]; List := g_list_first(List); g_list_foreach (list, TGFunc(@gtk_tree_path_free), nil); g_list_free (list); end else Result:=-1; end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; LM_GETITEMS : begin case TControl(Sender).fCompStyle of csComboBox: Result:=longint(gtk_object_get_data(PGtkObject(Handle),'LCLList')); csCheckListBox, csListBox: begin if TControl(Sender).fCompStyle = csCheckListBox then TempInt := 1 else TempInt := 0; Widget:= GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model(GTK_TREE_VIEW(Widget)); Data:= TGtkListStoreStringList.Create(GTK_LIST_STORE(aTreeModel), TempInt, TWinControl(Sender)); if Sender is TCustomListBox then TGtkListStoreStringList(Data).Sorted:=TCustomListBox(Sender).Sorted; Result:= Integer(Data); end; else raise Exception.Create('Message LM_GETITEMS - Not implemented'); end; end; LM_GETSEL : begin Result := 0; { assume: nothing found } if (Sender is TControl) and Assigned (data) then case TControl(Sender).fCompStyle of csListBox, csCheckListBox: begin { Get the child in question of that index } Widget := GetWidgetInfo(Pointer(Handle),True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model(GTK_TREE_VIEW(Widget)); aTreeSelect := gtk_tree_view_get_selection(GTK_TREE_VIEW(Widget)); if (aTreeModel <> nil) and (aTreeSelect <> nil) and (gtk_tree_model_iter_nth_child(aTreeModel,@aTreeIter, nil, Integer(Data^))) and (gtk_tree_selection_iter_is_selected(aTreeSelect, @aTreeIter)) then result := 1; end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; LM_GETSELSTART : begin if (Sender is TControl) then begin case TControl(Sender).fCompStyle of csMemo: begin Widget:= GetWidgetInfo(Pointer(Handle), true)^.CoreWidget; aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); gtk_text_buffer_get_selection_bounds(aTextBuffer, @aTextIter1, nil); result := gtk_text_iter_get_offset(@aTextIter1); end; csEdit: begin Widget:= GTK_WIDGET(Pointer(Handle)); if not gtk_editable_get_selection_bounds(GTK_EDITABLE(Widget),@result, nil) then result := gtk_editable_get_position(GTK_EDITABLE(Widget)); end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end end else Result:= 0; end; LM_GETSELCOUNT : begin case (Sender as TControl).fCompStyle of csListBox, csCheckListBox : begin Widget := GetWidgetInfo(Pointer(Handle),True)^.CoreWidget; aTreeSelect := gtk_tree_view_get_selection(GTK_TREE_VIEW(Widget)); {$IfNDef GTK2_2} Result := 0; gtk_tree_selection_selected_foreach(aTreeSelect, TGtkTreeSelectionForeachFunc(@gtkTreeSelectionCountSelectedRows), @Result); {$Else} Result := gtk_tree_selection_count_selected_rows(aTreeSelect); {$EndIf} end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; LM_GETSELLEN : begin if (Sender is TControl) then begin case TControl(Sender).fCompStyle of csMemo: begin Widget:= GetWidgetInfo(Pointer(Handle), true)^.CoreWidget; aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); gtk_text_buffer_get_selection_bounds(aTextBuffer, @aTextIter1, @aTextIter2); result:= Abs(gtk_text_iter_get_offset(@aTextIter2) - gtk_text_iter_get_offset(@aTextIter1)); end; csEdit: begin Widget:= GTK_WIDGET(Pointer(Handle)); if gtk_editable_get_selection_bounds(GTK_EDITABLE(Widget),@result, @TempInt) then result := TempInt - Result else result := 0; end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; end; LM_SETBORDER: begin if (Sender is TWinControl) then begin if (TControl(Sender).fCompStyle in [csListBox, csCListBox, csCheckListBox]) then begin Widget:= PGtkWidget(TWinControl(Sender).Handle); if TListBox(Sender).BorderStyle = TBorderStyle(bsSingle) then gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(Widget), GTK_SHADOW_IN) else gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(Widget), GTK_SHADOW_NONE); end end; end; LM_SETITEMINDEX: if Handle<>0 then begin case TControl(Sender).fCompStyle of csListBox, csCheckListBox: begin Widget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model(GTK_TREE_VIEW(Widget)); aTreeSelect := gtk_tree_view_get_selection(GTK_TREE_VIEW(Widget)); if (aTreeModel <> nil) and (aTreeSelect <> nil) then begin if (Integer(Data)>=0) and (gtk_tree_model_iter_nth_child(aTreeModel,@aTreeIter, nil, Integer(Data))) then gtk_tree_selection_select_iter(aTreeSelect, @aTreeIter) else gtk_tree_selection_unselect_all(aTreeSelect); end; end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; LM_SETSEL: begin if (Sender is TControl) and Assigned (data) then case TControl(Sender).fCompStyle of csListBox, csCheckListBox: begin Widget := GetWidgetInfo(Pointer(Handle), True)^.CoreWidget; aTreeModel := gtk_tree_view_get_model(GTK_TREE_VIEW(Widget)); aTreeSelect := gtk_tree_view_get_selection(GTK_TREE_VIEW(Widget)); if (aTreeModel <> nil) and (aTreeSelect <> nil) and (gtk_tree_model_iter_nth_child(aTreeModel,@aTreeIter, nil, TLMSetSel(Data^).Index)) then if TLMSetSel(Data^).Selected then gtk_tree_selection_select_iter(aTreeSelect, @aTreeIter) else if gtk_tree_selection_iter_is_selected(aTreeSelect, @aTreeIter) then gtk_tree_selection_unselect_iter(aTreeSelect, @aTreeIter); end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; LM_SETSELSTART: begin if (Sender is TControl) then begin case TControl(Sender).fCompStyle of csMemo: begin Widget:= GetWidgetInfo(Pointer(Handle), true)^.CoreWidget; aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); Debugln('TODO(GTK2): IntSendMessage3, LM_SETSELSTART, csMemo'); {gtk_text_buffer_get_selection_bounds(aTextBuffer, @aTextIter1, nil); result := gtk_text_iter_get_offset(@aTextIter1);} end; csEdit: begin Widget:= GTK_WIDGET(Pointer(Handle)); if gtk_editable_get_selection_bounds(GTK_EDITABLE(Widget),nil, @TempInt) then If (Integer(Data) >= 0) and (Integer(Data)<=TempInt) then gtk_editable_select_region(GTK_EDITABLE(Widget), Integer(Data), TempInt+1); end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end else Result:= 0; end; LM_SETSELLEN : begin if (Sender is TControl) then begin case TControl(Sender).fCompStyle of csMemo: begin Widget:= GetWidgetInfo(Pointer(Handle), true)^.CoreWidget; aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); Debugln('TODO(GTK2): IntSendMessage3, LM_SETSELLEN, csMemo'); {gtk_text_buffer_get_selection_bounds(aTextBuffer, @aTextIter1, @aTextIter2); result:= Abs(gtk_text_iter_get_offset(@aTextIter2) - gtk_text_iter_get_offset(@aTextIter1));} end; csEdit: begin Widget:= GTK_WIDGET(Pointer(Handle)); if gtk_editable_get_selection_bounds(GTK_EDITABLE(Widget),@TempInt, nil) then gtk_editable_select_region(GTK_EDITABLE(Widget), TempInt, TempInt+Integer(Data)+1) else gtk_editable_select_region(GTK_EDITABLE(Widget), gtk_editable_get_position(GTK_EDITABLE(Widget)), gtk_editable_get_position(GTK_EDITABLE(Widget)) + Integer(Data)+1) end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end; end; end; LM_SORT: begin if (Sender is TControl) and assigned (data) then begin case TControl(Sender).fCompStyle of csListBox, csCheckListBox : TGtkListStoreStringList(TLMSort(Data^).List).Sorted:= TLMSort(Data^).IsSorted; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; end end end; else begin result := inherited IntSendMessage3(LM_Message, Sender, data); exit; end; // end of else-part of 2nd case end; // end of 2nd case end; // end of else-part of 1st case // end; // end of 1st case end; {------------------------------------------------------------------------------ Function: TGtk2WidgetSet.SetCallback Params: Msg - message for which to set a callback sender - object to which callback will be send Returns: nothing Applies a Message to the sender ------------------------------------------------------------------------------} procedure TGTK2WidgetSet.SetCallback(const AMsg: LongInt; const AGTKObject: PGTKObject; const ALCLObject: TObject); procedure ConnectSenderSignal(const AnObject:PGTKObject; const ASignal: PChar; const ACallBackProc: Pointer); begin ConnectSignal(AnObject,ASignal,ACallBackProc,TComponent(ALCLObject)); end; procedure ConnectSenderSignalAfter(const AnObject:PGTKObject; const ASignal: PChar; const ACallBackProc: Pointer); begin ConnectSignalAfter(AnObject,ASignal,ACallBackProc,TComponent(ALCLObject)); end; procedure ConnectSenderSignal(const AnObject:PGTKObject; const ASignal: PChar; const ACallBackProc: Pointer; const ReqSignalMask: TGdkEventMask); begin ConnectSignal(AnObject,ASignal,ACallBackProc,ALCLObject, ReqSignalMask); end; procedure ConnectSenderSignalAfter(const AnObject:PGTKObject; const ASignal: PChar; const ACallBackProc: Pointer; const ReqSignalMask: TGdkEventMask); begin ConnectSignalAfter(AnObject,ASignal,ACallBackProc,ALCLObject, ReqSignalMask); end; procedure ConnectFocusEvents(const AnObject: PGTKObject); begin ConnectSenderSignal(AnObject, 'focus-in-event', @gtk2FocusCB); ConnectSenderSignalAfter(AnObject, 'focus-in-event', @gtk2FocusCBAfter); ConnectSenderSignal(AnObject, 'focus-out-event', @gtk2KillFocusCB); ConnectSenderSignalAfter(AnObject, 'focus-out-event', @gtk2KillFocusCBAfter); end; procedure ConnectKeyPressReleaseEvents(const AnObject: PGTKObject); begin ConnectSenderSignal(AnObject, 'key-press-event', @GTK2KeyUpDown, GDK_KEY_PRESS_MASK); //ConnectSenderSignalAfter(AnObject, // 'key-press-event', @GTK2KeyUpDownAfter, GDK_KEY_PRESS_MASK); ConnectSenderSignal(AnObject, 'key-release-event', @GTK2KeyUpDown, GDK_KEY_RELEASE_MASK); //ConnectSenderSignalAfter(AnObject, // 'key-release-event', @GTK2KeyUpDownAfter, GDK_KEY_RELEASE_MASK); end; var gObject, gFixed, gCore, Scroll: PGTKObject; begin gObject := AGTKObject; if gObject = nil then Exit; // gFixed is the widget with the client area (e.g. TGroupBox, TForm have this) gFixed := PGTKObject(GetFixedWidget(gObject)); if gFixed = nil then gFixed := gObject; // gCore is the main widget (e.g. TListView has this) gCore:= PGtkObject(GetWidgetInfo(gObject, True)^.CoreWidget); case AMsg of LM_FOCUS : begin if (ALCLObject is TCustomComboBox) then begin ConnectFocusEvents(PgtkObject(PgtkCombo(gObject)^.entry)); ConnectFocusEvents(PgtkObject(PgtkCombo(gObject)^.list)); end else begin ConnectFocusEvents(gCore); end; end; LM_CHAR, LM_KEYDOWN, LM_KEYUP, LM_SYSCHAR, LM_SYSKEYDOWN, LM_SYSKEYUP: begin if (ALCLObject is TCustomComboBox) then begin ConnectKeyPressReleaseEvents(PgtkObject(PgtkCombo(gObject)^.entry)); end else if (ALCLObject is TCustomForm) then begin ConnectKeyPressReleaseEvents(gObject); end; ConnectKeyPressReleaseEvents(gCore); end; LM_SHOWWINDOW : begin ConnectSenderSignal(gObject, 'show', @gtk2showCB); ConnectSenderSignal(gObject, 'hide', @gtk2hideCB); end; else Inherited SetCallback(AMsg, AGTKObject, ALCLObject); end; end; Function TGtk2WidgetSet.LoadStockPixmap(StockID: longint) : HBitmap; var Pixmap : PGDIObject; StockName : PChar; IconSet : PGtkIconSet; Pixbuf : PGDKPixbuf; begin Case StockID Of idButtonOk : StockName := GTK_STOCK_OK; idButtonCancel : StockName := GTK_STOCK_CANCEL; idButtonYes : StockName := GTK_STOCK_YES; idButtonNo : StockName := GTK_STOCK_NO; idButtonHelp : StockName := GTK_STOCK_HELP; idButtonAbort : StockName := GTK_STOCK_CANCEL; idButtonClose : StockName := GTK_STOCK_QUIT; idDialogWarning : StockName := GTK_STOCK_DIALOG_WARNING; idDialogError : StockName := GTK_STOCK_DIALOG_ERROR; idDialogInfo : StockName := GTK_STOCK_DIALOG_INFO; idDialogConfirm : StockName := GTK_STOCK_DIALOG_QUESTION; else begin Result := inherited LoadStockPixmap(StockID); exit; end; end; if (StockID >= idButtonBase) and (StockID <= idDialogBase) then IconSet := gtk_style_lookup_icon_set(GetStyle(lgsButton), StockName) else IconSet := gtk_style_lookup_icon_set(GetStyle(lgsWindow), StockName); If (IconSet = nil) then begin Result := inherited LoadStockPixmap(StockID); exit; end; if (StockID >= idButtonBase) and (StockID <= idDialogBase) then pixbuf := gtk_icon_set_render_icon(IconSet, GetStyle(lgsbutton), GTK_TEXT_DIR_NONE, GTK_STATE_NORMAL, GTK_ICON_SIZE_BUTTON, GetStyleWidget(lgsbutton), nil) else pixbuf := gtk_icon_set_render_icon(IconSet, GetStyle(lgswindow), GTK_TEXT_DIR_NONE, GTK_STATE_NORMAL, GTK_ICON_SIZE_DIALOG, GetStyleWidget(lgswindow), nil); Pixmap := NewGDIObject(gdiBitmap); 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, GDIBitmapMaskObject, 128); end; gdk_pixbuf_unref(pixbuf); Result := HBitmap(Pixmap); end; {------------------------------------------------------------------------------ Method: TGtk2WidgetSet.SetLabel Params: sender - the calling object data - String (PChar) to be set as label for a control Returns: Nothing Sets the label text on a widget ------------------------------------------------------------------------------} procedure TGtk2WidgetSet.SetLabel(Sender : TObject; Data : Pointer); var Widget : PGtkWidget; aTextBuffer : PGtkTextBuffer; aTextIter1 : TGtkTextIter; aTextIter2 : TGtkTextIter; DC : hDC; aLabel, pLabel: pchar; AccelKey : integer; begin if Sender is TMenuItem then begin inherited SetLabel(Sender, Data); exit; end; if Sender is TWinControl then Assert(False, Format('Trace: [TGtk2WidgetSet.SetLabel] %s --> label %s', [Sender.ClassName, TControl(Sender).Caption])) else begin Assert(False, Format('Trace:WARNING: [TGtk2WidgetSet.SetLabel] %s --> No Decendant of TWinControl', [Sender.ClassName])); RaiseException('[TGtk2WidgetSet.SetLabel] ERROR: Sender ('+Sender.Classname+')' +' is not TWinControl '); end; Widget := PGtkWidget(TWinControl(Sender).Handle); Assert(Widget = nil, 'Trace:WARNING: [TGtk2WidgetSet.SetLabel] --> got nil pointer'); Assert(False, 'Trace:Setting Str1 in SetLabel'); pLabel := pchar(Data); case TControl(Sender).fCompStyle of csEdit : begin gtk_entry_set_text(pGtkEntry(Widget), pLabel); {LockOnChange(PGtkObject(Widget),+1); gtk_editable_delete_text(pGtkEditable(P), 0, -1); gtk_editable_insert_text(pGtkEditable(P), pLabel, StrLen(pLabel). 0); LockOnChange(PGtkObject(Widget),-1);} end; csLabel: begin gtk_label_set_use_underline(PGtkLabel(Widget), True); if TLabel(Sender).ShowAccelChar then begin If TLabel(sender).WordWrap and (TLabel(Sender).Caption<>'') then begin DC := GetDC(TLabel(Sender).Handle); aLabel := ForceLineBreaks(DC, pLabel, TLabel(Sender).Width, True); DeleteDC(DC); end else aLabel:= Ampersands2Underscore(pLabel); try gtk_label_set_label(pGtkLabel(Widget), aLabel); AccelKey:= gtk_label_get_mnemonic_keyval(pGtkLabel(Widget)); Accelerate(TComponent(Sender),Widget,AccelKey,0,'grab_focus'); finally StrDispose(aLabel); end; end else begin If TLabel(sender).WordWrap then begin DC := GetDC(TLabel(Sender).Handle); aLabel := ForceLineBreaks(DC, pLabel, TLabel(Sender).Width, False); gtk_label_set_label(PGtkLabel(Widget), aLabel); StrDispose(aLabel); DeleteDC(DC); end else gtk_label_set_label(PGtkLabel(Widget), pLabel); end; end; csMemo : begin Widget:= PGtkWidget(GetWidgetInfo(Widget, True)^.CoreWidget); aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(Widget)); gtk_text_buffer_begin_user_action(aTextBuffer); gtk_text_buffer_get_bounds(aTextBuffer, @aTextIter1, @aTextIter2); gtk_text_buffer_delete(aTextBuffer, @aTextIter1, @aTextIter2); gtk_text_buffer_get_bounds(aTextBuffer, @aTextIter1, @aTextIter2); gtk_text_buffer_insert(aTextBuffer, @aTextIter1, pLabel, StrLen(pLabel)); gtk_text_buffer_end_user_action(aTextBuffer); end; else inherited SetLabel(Sender, Data); end; Assert(False, Format('trace: [TGtk2WidgetSet.SetLabel] %s --> END', [Sender.ClassName])); end; {------------------------------------------------------------------------------ Method: TGtk2WidgetSet.SetProperties Params: Sender : the lcl object which called this func via SenMessage Returns: currently always 0 Depending on the compStyle, this function will apply all properties of the calling object to the corresponding GTK2 object. ------------------------------------------------------------------------------} function TGtk2WidgetSet.SetProperties(Sender : TObject) : integer; const cLabelAlignX : array[TAlignment] of gfloat = (0.0, 1.0, 0.5); cLabelAlignY : array[TTextLayout] of gfloat = (0.0, 0.5, 1.0); cLabelAlign : array[TAlignment] of TGtkJustification = (GTK_JUSTIFY_LEFT, GTK_JUSTIFY_RIGHT, GTK_JUSTIFY_CENTER); var wHandle : Pointer; Widget, ImplWidget : PGtkWidget; i : Longint; aTextBuffer : PGtkTextBuffer; aTextIter1 : TGtkTextIter; aTextIter2 : TGtkTextIter; begin Result := 0; // default if nobody sets it if Sender is TWinControl then Assert(False, Format('Trace: [TGtk2WidgetSet.SetProperties] %s', [Sender.ClassName])) else RaiseException('TGtk2WidgetSet.SetProperties: ' +' Sender.ClassName='+Sender.ClassName); wHandle:= Pointer(TWinControl(Sender).Handle); Widget:= GTK_WIDGET(wHandle); case TControl(Sender).fCompStyle of csEdit : with TCustomEdit(Sender) do begin gtk_editable_set_editable(GTK_ENTRY(wHandle), not (TCustomEdit(Sender).ReadOnly)); gtk_entry_set_max_length(GTK_ENTRY(wHandle), TCustomEdit(Sender).MaxLength); gtk_entry_set_visibility(GTK_ENTRY(wHandle), (TCustomEdit(Sender).EchoMode = emNormal) and (TCustomEdit(Sender).PassWordChar=#0)); if (TCustomEdit(Sender).EchoMode = emNone) then gtk_entry_set_invisible_char(GTK_ENTRY(wHandle), 0) else gtk_entry_set_invisible_char(GTK_ENTRY(wHandle), Longint(TCustomEdit(Sender).PassWordChar)); end; csLabel : with TLabel(Sender) do begin gtk_label_set_line_wrap(GTK_LABEL(wHandle), False); gtk_misc_set_alignment(GTK_MISC(wHandle), cLabelAlignX[Alignment], 0.0); gtk_label_set_line_wrap(GTK_LABEL(wHandle), TRUE); gtk_label_set_justify(GTK_LABEL(wHandle), cLabelAlign[Alignment]); end; csMemo: begin ImplWidget:= GetWidgetInfo(wHandle, true)^.CoreWidget; gtk_text_view_set_editable (PGtkTextView(ImplWidget), not TCustomMemo(Sender).ReadOnly); if TCustomMemo(Sender).WordWrap then gtk_text_view_set_wrap_mode(PGtkTextView(ImplWidget), GTK_WRAP_WORD) else gtk_text_view_set_wrap_mode(PGtkTextView(ImplWidget), GTK_WRAP_NONE); case (Sender as TCustomMemo).Scrollbars of ssHorizontal: gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_ALWAYS, GTK_POLICY_NEVER); ssVertical: gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_NEVER, GTK_POLICY_ALWAYS); ssBoth: gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS); ssAutoHorizontal: gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_AUTOMATIC, GTK_POLICY_NEVER); ssAutoVertical: gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); ssAutoBoth: gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); else gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(wHandle), GTK_POLICY_NEVER, GTK_POLICY_NEVER); end; If (TCustomMemo(Sender).MaxLength >= 0) then begin aTextBuffer := gtk_text_view_get_buffer(GTK_TEXT_VIEW(ImplWidget)); i:= gtk_text_buffer_get_char_count(aTextBuffer); if i > TCustomMemo(Sender).MaxLength then begin gtk_text_buffer_get_bounds(aTextBuffer, nil, @aTextIter2); gtk_text_buffer_get_iter_at_offset(aTextBuffer, @aTextIter1, i); gtk_text_buffer_delete(aTextBuffer, @aTextIter1, @aTextIter2); end; end; end; else Result := inherited SetProperties(Sender); end; end; {------------------------------------------------------------------------------ procedure TGtk2WidgetSet.SetSelectionMode(Sender: TObject; Widget: PGtkWidget; MultiSelect, ExtendedSelect: boolean); ------------------------------------------------------------------------------} procedure TGtk2WidgetSet.SetSelectionMode(Sender: TObject; Widget: PGtkWidget; MultiSelect, ExtendedSelect: boolean); var AControl: TWinControl; SelectionMode: TGtkSelectionMode; Selection : PGtkTreeSelection; begin AControl:=TWinControl(Sender); if (AControl is TWinControl) and (AControl.fCompStyle in [csListBox, csCheckListBox, csCListBox]) then begin if MultiSelect then SelectionMode:= GTK_SELECTION_MULTIPLE else SelectionMode:= GTK_SELECTION_SINGLE; case AControl.fCompStyle of csListBox, csCheckListBox: begin Selection := gtk_tree_view_get_selection(GTK_TREE_VIEW( GetWidgetInfo(Widget, True)^.CoreWidget)); gtk_tree_selection_set_mode(Selection, SelectionMode); end; else inherited SetSelectionMode(Sender, Widget, MultiSelect, ExtendedSelect); end; end; end; {------------------------------------------------------------------------------ function TGtk2WidgetSet.SetTopIndex(Sender: TObject; NewTopIndex: integer ): integer; ------------------------------------------------------------------------------} function TGtk2WidgetSet.SetTopIndex(Sender: TObject; NewTopIndex: integer ): integer; var aTreeView: PGtkTreeView; aTreeModel : PGtkTreeModel; aTreeColumn : PGtkTreeViewColumn; aTreeIter : TGtkTreeIter; aTreePath : PGtkTreePath; Count : Integer; begin Result:=0; if not (Sender is TWinControl) then exit; case TWinControl(Sender).fCompStyle of csListBox, csCheckListBox: begin aTreeView := GTK_TREE_VIEW(GetWidgetInfo(Pointer(TWinControl(Sender).Handle), True)^.CoreWidget); aTreeModel := gtk_tree_view_get_model(aTreeView); If NewTopIndex < 0 then NewTopIndex := 0 else begin Count := gtk_tree_model_iter_n_children(aTreeModel,nil); If NewTopIndex >= Count then NewTopIndex := Count - 1; end; if gtk_tree_model_iter_nth_child(aTreeModel,@aTreeIter, nil, NewTopIndex) then begin aTreePath := gtk_tree_model_get_path(aTreeModel, @aTreeIter); aTreeColumn := gtk_tree_view_get_column(aTreeView, 0); gtk_tree_view_scroll_to_cell(aTreeView, aTreePath, aTreeColumn, False, 0.0, 0.0); gtk_tree_path_free(aTreePath); end; end; end; end; {------------------------------------------------------------------------------ procedure TGtk2WidgetSet.UpdateDCTextMetric(DC: TDeviceContext); ------------------------------------------------------------------------------} procedure TGtk2WidgetSet.UpdateDCTextMetric(DC: TDeviceContext); const TestString = '{Am|g_}'; var XT : TSize; dummy: LongInt; UseFontDesc : PPangoFontDescription; UnRef : Boolean; AVGBuffer: array[#32..#126] of char; AvgLen: integer; c: char; Underline, StrikeOut : Boolean; Layout : PPangoLayout; AttrList : PPangoAttrList; Attr : PPangoAttribute; Extents : TPangoRectangle; begin with TDeviceContext(DC) do begin if dcfTextMetricsValid in DCFlags then begin // cache valid end else begin if (CurrentFont = nil) or (CurrentFont^.GDIFontObject = nil) then begin UseFontDesc := GetDefaultFontDesc(true); UnRef := True; Underline := False; StrikeOut := False; end else begin UseFontDesc := CurrentFont^.GDIFontObject; UnRef := False; Underline := CurrentFont^.Underline; StrikeOut := CurrentFont^.StrikeOut; end; If UseFontDesc = nil then DebugLn('WARNING: [TGtk2WidgetSet.GetTextMetrics] Missing font') else begin Layout := gtk_widget_create_pango_layout (GetStyleWidget(lgsdefault), nil); pango_layout_set_font_description(Layout, UseFontDesc); AttrList := pango_layout_get_attributes(Layout); If (AttrList = nil) then AttrList := pango_attr_list_new(); //fix me... what about &&, can we strip and do do markup substitution? If Underline then Attr := pango_attr_underline_new(PANGO_UNDERLINE_SINGLE) else Attr := pango_attr_underline_new(PANGO_UNDERLINE_NONE); pango_attr_list_change(AttrList,Attr); Attr := pango_attr_strikethrough_new(StrikeOut); pango_attr_list_change(AttrList,Attr); pango_layout_set_attributes(Layout, AttrList); pango_layout_set_single_paragraph_mode(Layout, TRUE); pango_layout_set_width(Layout, -1); pango_layout_set_alignment(Layout, PANGO_ALIGN_LEFT); //fix me... and what about UTF-8 conversion? //this could be a massive problem since we //will need to know before hand what the current //locale is, and if we stored UTF-8 string this would break //cross-compatibility with GTK1.2 and win32 interfaces..... pango_layout_set_text(Layout, TestString, length(TestString)); pango_layout_get_extents(Layout, nil, @Extents); g_object_unref(Layout); If UnRef then pango_font_description_free(UseFontDesc); FillChar(DCTextMetric, SizeOf(DCTextMetric), 0); with DCTextMetric do begin IsDoubleByteChar:=False;//FontIsDoubleByteCharsFont(UseFont); for c:=Low(AVGBuffer) to High(AVGBuffer) do AVGBuffer[c]:=c; lbearing := PANGO_LBEARING(extents) div PANGO_SCALE; rBearing := PANGO_RBEARING(extents) div PANGO_SCALE; TextMetric.tmAscent := PANGO_ASCENT(extents) div PANGO_SCALE; TextMetric.tmDescent := PANGO_DESCENT(extents) div PANGO_SCALE; AvgLen:=ord(High(AVGBuffer))-ord(Low(AVGBuffer))+1; GetTextExtentPoint(HDC(DC), @AVGBuffer[Low(AVGBuffer)], AvgLen, XT); if not IsDoubleByteChar then XT.cX := XT.cX div AvgLen else // Quick hack for double byte char fonts XT.cX := XT.cX div (AvgLen div 2); TextMetric.tmHeight := XT.cY; TextMetric.tmAscent := TextMetric.tmHeight - TextMetric.tmDescent; TextMetric.tmAveCharWidth := XT.cX; if TextMetric.tmAveCharWidth<1 then TextMetric.tmAveCharWidth:=1; {temp EVIL hack FIXME -->} AVGBuffer[Low(AVGBuffer)]:='M'; GetTextExtentPoint(HDC(DC), @AVGBuffer[Low(AVGBuffer)], 1, XT); TextMetric.tmMaxCharWidth := XT.cX; AVGBuffer[Low(AVGBuffer)]:='W'; GetTextExtentPoint(HDC(DC), @AVGBuffer[Low(AVGBuffer)], 1, XT); TextMetric.tmMaxCharWidth := Max(TextMetric.tmMaxCharWidth,XT.cX); {<-- temp EVIL hack FIXME} if TextMetric.tmMaxCharWidth<1 then TextMetric.tmMaxCharWidth:=1; end; end; Include(DCFlags,dcfTextMetricsValid); end; end; end; {$IFDEF ASSERT_IS_ON} {$UNDEF ASSERT_IS_ON} {$C-} {$ENDIF} { ============================================================================= $Log$ Revision 1.12 2004/05/22 14:35:33 mattias fixed button return key Revision 1.11 2004/05/11 09:49:47 mattias started sending CN_KEYUP Revision 1.10 2004/04/13 14:03:29 marc Patch from Ladislav Michl Revision 1.9 2004/03/09 15:30:15 peter * fixed gtk2 compilation Revision 1.8 2004/03/05 00:41:15 marc * Renamed TGtk2Object to TGtk2WidgetSet Revision 1.7 2004/01/04 16:44:33 mattias updated gtk2 package Revision 1.6 2003/10/04 00:36:30 ajgenius partly fix csLabel for GTK2, Layout is still wacked. Revision 1.5 2003/10/03 01:25:01 ajgenius add more gtk1i<->gtk2 key & event wrappers, move more GTK2 workarounds from gtk to gtk2 interface, start GTK2 interface SetCallback Revision 1.4 2003/10/02 18:15:44 ajgenius more gtk2 (check)ListBox implementation Revision 1.3 2003/10/02 01:18:38 ajgenius more callbacks fixes for gtk2, partly fix gtk2 CheckListBox Revision 1.2 2003/09/24 17:23:54 ajgenius more work toward GTK2 - partly fix CheckListBox, & MenuItems Revision 1.1 2003/09/22 20:08:56 ajgenius break GTK2 object and winapi into includes like the GTK interface }