aboutsummaryrefslogtreecommitdiff
path: root/src/findbar.cc
blob: f0d23d018870533b6b9d6b94661b5d69b82bd92a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/*
 * File: findbar.cc
 *
 * Copyright (C) 2005-2007 Jorge Arellano Cid <jcid@dillo.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 */

#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include "findbar.hh"

#include "msg.h"
#include "pixmaps.h"
#include "uicmd.hh"
#include "bw.h"

/*
 * Local sub class
 * (Used to handle escape in the findbar, may also avoid some shortcuts).
 */
class MyInput : public Fl_Input {
public:
   MyInput (int x, int y, int w, int h, const char* l=0) :
      Fl_Input(x,y,w,h,l) {};
   int handle(int e);
};

int MyInput::handle(int e)
{
   _MSG("findbar MyInput::handle()\n");
   int ret = 1, k = Fl::event_key();
   unsigned modifier = Fl::event_state() & (FL_SHIFT| FL_CTRL| FL_ALT|FL_META);

   if (e == FL_KEYBOARD) {
      if (k == FL_Page_Down || k == FL_Page_Up || k == FL_Up || k == FL_Down) {
         // Let them through for key commands and viewport motion.
         return 0;
      }
      if (modifier == FL_SHIFT) {
         if (k == FL_Left || k == FL_Right) {
            // Let these keys get to the UI
            return 0;
         }
      } else if (modifier == FL_CTRL) {
         if (k == 'a' || k == 'e') {
            position(k == 'a' ? 0 : size());
            return 1;
         } else if (k == 'k') {
            cut(position(), size());
            return 1;
         } else if (k == 'd') {
            cut(position(), position()+1);
            return 1;
         } else if (k == 'h' || k == 'i' || k == 'j' || k == 'l' || k == 'm') {
            // Fl_Input wants to use ^H as backspace, and also "insert a few
            // selected control characters literally", but this gets in the way
            // of key commands.
            return 0;
         }
      } else if (k == FL_Escape && modifier == 0) {
         // Avoid clearing the text with Esc, just hide the findbar.
         return 0;
      }
   }

   if (ret)
      ret = Fl_Input::handle(e);
   return ret;
}

/**
 * Find next occurrence of input key
 */
void Findbar::search_cb(Fl_Widget *, void *vfb)
{
   Findbar *fb = (Findbar *)vfb;
   const char *key = fb->i->value();
   bool case_sens = fb->check_btn->value();

   if (key[0] != '\0')
      a_UIcmd_findtext_search(a_UIcmd_get_bw_by_widget(fb),
                              key, case_sens, false);
}

/**
 * Find previous occurrence of input key
 */
void Findbar::searchBackwards_cb(Fl_Widget *, void *vfb)
{
   Findbar *fb = (Findbar *)vfb;
   const char *key = fb->i->value();
   bool case_sens = fb->check_btn->value();

   if (key[0] != '\0') {
      a_UIcmd_findtext_search(a_UIcmd_get_bw_by_widget(fb),
                              key, case_sens, true);
   }
}

/**
 * Hide the search bar
 */
void Findbar::hide_cb(Fl_Widget *, void *vfb)
{
   a_UIcmd_findbar_toggle(a_UIcmd_get_bw_by_widget(vfb), 0);
}

/**
 * Construct text search bar
 */
Findbar::Findbar(int width, int height) :
   Fl_Group(0, 0, width, height)
{
   int button_width = 70;
   int gap = 2;
   int border = 2;
   int input_width = width - (2 * border + 4 * (button_width + gap));
   int x = 0;

   Fl_Group::current(0);

   height -= 2 * border;

   box(FL_THIN_UP_BOX);

    hide_btn = new CustButton(x, border, 16, height, 0);
    hideImg = new Fl_Pixmap(new_s_xpm);
    hide_btn->image(hideImg);
    x += 16 + gap;
    hide_btn->callback(hide_cb, this);
    hide_btn->clear_visible_focus();
    hide_btn->box(FL_THIN_UP_BOX);
    hide_btn->set_tooltip("Hide");
   add(hide_btn);

    i = new MyInput(x, border, input_width, height);
    x += input_width + gap;
    resizable(i);
    i->when(FL_WHEN_NEVER);
   add(i);

    next_btn = new CustButton(x, border, button_width, height, "Next");
    x += button_width + gap;
    next_btn->shortcut(FL_Enter);
    next_btn->callback(search_cb, this);
    next_btn->clear_visible_focus();
    next_btn->box(FL_THIN_UP_BOX);
    next_btn->set_tooltip("Find next occurrence of the search phrase\n"
                          "shortcut: Enter");
   add(next_btn);

    prev_btn= new CustButton(x, border, button_width, height, "Previous");
    x += button_width + gap;
    prev_btn->shortcut(FL_SHIFT+FL_Enter);
    prev_btn->callback(searchBackwards_cb, this);
    prev_btn->clear_visible_focus();
    prev_btn->box(FL_THIN_UP_BOX);
    prev_btn->set_tooltip("Find previous occurrence of the search phrase\n"
                          "shortcut: Shift+Enter");
   add(prev_btn);

    check_btn = new Fl_Check_Button(x, border, 2*button_width, height,
                              "Case-sensitive");
    x += 2 * button_width + gap;
    check_btn->clear_visible_focus();
   add(check_btn);

}

Findbar::~Findbar()
{
   delete hideImg;
}

/**
 * Handle events. Used to catch FL_Escape events.
 */
int Findbar::handle(int event)
{
   int k = Fl::event_key();
   unsigned modifier = Fl::event_state() & (FL_SHIFT| FL_CTRL| FL_ALT|FL_META);

   if (event == FL_KEYBOARD && modifier == 0 && k == FL_Escape) {
      /* let the UI handle it */
      return 0;
   }

   return Fl_Group::handle(event);
}

/**
 * Show the findbar and focus the input field
 */
void Findbar::show()
{
   BrowserWindow *bw = a_UIcmd_get_bw_by_widget(this);
   dReturn_if (bw == NULL);

   // It takes more than just calling show() to do the trick
   Fl_Group::show();

   /* select text even if already focused */
   i->take_focus();
   i->position(i->size(), 0);
}