5
// Aaron Bockover <abockover@novell.com>
6
// Gabriel Burt <gburt@novell.com>
8
// Copyright (C) 2007 Novell, Inc.
10
// Permission is hereby granted, free of charge, to any person obtaining
11
// a copy of this software and associated documentation files (the
12
// "Software"), to deal in the Software without restriction, including
13
// without limitation the rights to use, copy, modify, merge, publish,
14
// distribute, sublicense, and/or sell copies of the Software, and to
15
// permit persons to whom the Software is furnished to do so, subject to
16
// the following conditions:
18
// The above copyright notice and this permission notice shall be
19
// included in all copies or substantial portions of the Software.
21
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
public class SearchEntry : EventBox
39
private HoverImageButton clear_button;
41
private uint changed_timeout_id = 0;
43
private string empty_message;
44
private bool ready = false;
46
private event EventHandler entry_changed;
48
public event EventHandler Changed {
49
add { entry_changed += value; }
50
remove { entry_changed -= value; }
53
public event EventHandler Activated {
54
add { entry.Activated += value; }
55
remove { entry.Activated -= value; }
67
private void BuildWidget()
70
entry = new FramelessEntry(this);
71
clear_button = new HoverImageButton(IconSize.Menu, new string [] { "edit-clear", Stock.Clear });
73
box.PackStart(entry, true, true, 0);
74
box.PackStart(clear_button, false, false, 0);
79
entry.StyleSet += OnInnerEntryStyleSet;
80
entry.StateChanged += OnInnerEntryStateChanged;
81
entry.FocusInEvent += OnInnerEntryFocusEvent;
82
entry.FocusOutEvent += OnInnerEntryFocusEvent;
83
entry.Changed += OnInnerEntryChanged;
85
clear_button.Image.Xpad = 2;
86
clear_button.CanFocus = false;
88
clear_button.ButtonReleaseEvent += OnButtonReleaseEvent;
89
clear_button.Clicked += OnClearButtonClicked;
91
clear_button.Visible = false;
94
private void ShowHideButtons()
96
clear_button.Visible = entry.Text.Length > 0;
99
private void OnInnerEntryChanged(object o, EventArgs args)
103
if(changed_timeout_id > 0) {
104
GLib.Source.Remove(changed_timeout_id);
108
changed_timeout_id = GLib.Timeout.Add(25, OnChangedTimeout);
111
private bool OnChangedTimeout()
117
private void UpdateStyle ()
119
Gdk.Color color = entry.Style.Base (entry.State);
120
clear_button.ModifyBg (entry.State, color);
122
box.BorderWidth = (uint)entry.Style.XThickness;
125
private void OnInnerEntryStyleSet (object o, StyleSetArgs args)
130
private void OnInnerEntryStateChanged (object o, EventArgs args)
135
private void OnInnerEntryFocusEvent(object o, EventArgs args)
140
private void OnButtonReleaseEvent(object o, ButtonReleaseEventArgs args)
142
if(args.Event.Button != 1) {
146
entry.HasFocus = true;
149
private void OnClearButtonClicked(object o, EventArgs args)
151
entry.Text = String.Empty;
154
protected override bool OnExposeEvent(Gdk.EventExpose evnt)
156
PropagateExpose(Child, evnt);
157
Style.PaintShadow(entry.Style, GdkWindow, StateType.Normal,
158
ShadowType.In, evnt.Area, entry, "entry",
159
0, 0, Allocation.Width, Allocation.Height);
163
protected override void OnShown()
169
protected virtual void OnChanged()
175
EventHandler handler = entry_changed;
176
if(handler != null) {
177
handler(this, EventArgs.Empty);
181
public string EmptyMessage {
182
get { return empty_message; }
184
empty_message = value;
189
public string Query {
190
get { return entry.Text.Trim(); }
191
set { entry.Text = value.Trim(); }
194
public bool IsQueryAvailable {
195
get { return Query != null && Query != String.Empty; }
199
get { return ready; }
200
set { ready = value; }
203
public new bool HasFocus {
204
get { return entry.HasFocus; }
205
set { entry.HasFocus = true; }
209
public Entry InnerEntry {
210
get { return entry; }
213
private class FramelessEntry : Entry
215
private Gdk.Window text_window;
216
private SearchEntry parent;
217
private Pango.Layout layout;
218
private Gdk.GC text_gc;
220
public FramelessEntry(SearchEntry parent) : base()
222
this.parent = parent;
225
layout = new Pango.Layout(PangoContext);
226
layout.FontDescription = PangoContext.FontDescription.Copy();
228
parent.StyleSet += OnParentStyleSet;
232
private void OnParentStyleSet(object o, EventArgs args)
238
private void RefreshGC()
240
if(text_window == null) {
244
text_gc = new Gdk.GC(text_window);
245
text_gc.Copy(Style.TextGC(StateType.Normal));
246
//Gdk.Color color_a = parent.Style.Base(StateType.Normal);
247
//Gdk.Color color_b = parent.Style.Text(StateType.Normal);
248
text_gc.RgbFgColor = new Gdk.Color (0,0,0);
249
//text_gc.RgbFgColor = Hyena.Gui.GtkUtilities.ColorBlend(color_a, color_b);
252
protected override bool OnExposeEvent(Gdk.EventExpose evnt)
254
// The Entry's GdkWindow is the top level window onto which
255
// the frame is drawn; the actual text entry is drawn into a
256
// separate window, so we can ensure that for themes that don't
257
// respect HasFrame, we never ever allow the base frame drawing
259
if(evnt.Window == GdkWindow) {
263
bool ret = base.OnExposeEvent(evnt);
265
if(text_gc == null || evnt.Window != text_window) {
266
text_window = evnt.Window;
270
if(Text.Length > 0 || HasFocus || parent.EmptyMessage == null) {
275
layout.SetMarkup(parent.EmptyMessage);
276
layout.GetPixelSize(out width, out height);
277
evnt.Window.DrawLayout(text_gc, 2, (SizeRequest().Height - height) / 2, layout);