Work at SourceForge, help us to make it a better place! We have an immediate need for a Support Technician in our San Francisco or Denver office.

Close

Diff of /src/highlight.c [267417] .. [52d456] Maximize Restore

  Switch to unified view

a/src/highlight.c b/src/highlight.c
1
/*
1
/* 
2
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
2
 * Copyright (C) 2000 Rich Wareham <richwareham@users.sourceforge.net>
3
 *
3
 * 
4
 * This file is part of libdvdnav, a DVD navigation library.
4
 * This file is part of libdvdnav, a DVD navigation library.
5
 *
5
 * 
6
 * libdvdnav is free software; you can redistribute it and/or modify
6
 * libdvdnav is free software; you can redistribute it and/or modify
7
 * it under the terms of the GNU General Public License as published by
7
 * it under the terms of the GNU General Public License as published by
8
 * the Free Software Foundation; either version 2 of the License, or
8
 * the Free Software Foundation; either version 2 of the License, or
9
 * (at your option) any later version.
9
 * (at your option) any later version.
10
 *
10
 * 
11
 * libdvdnav is distributed in the hope that it will be useful,
11
 * libdvdnav is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
14
 * GNU General Public License for more details.
15
 * 
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
15
 *
19
 *
16
 * You should have received a copy of the GNU General Public License along
20
 * $Id$
17
 * with libdvdnav; if not, write to the Free Software Foundation, Inc.,
21
 *
18
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
 */
22
 */
20
23
21
#ifdef HAVE_CONFIG_H
24
#ifdef HAVE_CONFIG_H
22
#include "config.h"
25
#include "config.h"
23
#endif
26
#endif
24
25
#include <assert.h>
26
#include <inttypes.h>
27
#include <stdlib.h>
28
#include <stdio.h>
29
#include <limits.h>
30
#include <string.h>
31
#include <sys/time.h>
32
#include <dvdread/nav_types.h>
33
#include "dvdnav/dvdnav.h"
34
#include "remap.h"
35
#include "vm/decoder.h"
36
#include "vm/vm.h"
37
#include "vm/vmcmd.h"
38
#include "dvdnav_internal.h"
39
27
40
/*
28
/*
41
#define BUTTON_TESTING
29
#define BUTTON_TESTING
42
*/
30
*/
43
31
32
#include <dvdnav.h>
33
#include "dvdnav_internal.h"
34
35
#include "vm.h"
36
#
37
#include <dvdread/nav_types.h>
38
44
#ifdef BUTTON_TESTING
39
#ifdef BUTTON_TESTING
45
46
#include "nav_print.h"
40
#include <dvdread/nav_print.h>
41
#endif
47
42
48
static void print_time(dvd_time_t *dtime) {
43
/* Highlighting API calls */
49
  const char *rate;
50
44
51
  assert((dtime->hour>>4) < 0xa && (dtime->hour&0xf) < 0xa);
45
dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *self, int* button) {
52
  assert((dtime->minute>>4) < 0x7 && (dtime->minute&0xf) < 0xa);
46
  if(!self)
53
  assert((dtime->second>>4) < 0x7 && (dtime->second&0xf) < 0xa);
47
   return S_ERR;
54
  assert((dtime->frame_u&0xf) < 0xa);
55
48
56
  fprintf(MSG_OUT,"%02x:%02x:%02x.%02x",
49
  /* Simply return the appropriate value based on the SPRM */
57
         dtime->hour,
50
  (*button) = (self->vm->state.HL_BTNN_REG) >> 10;
58
         dtime->minute,
59
         dtime->second,
60
         dtime->frame_u & 0x3f);
61
  switch((dtime->frame_u & 0xc0) >> 6) {
62
  case 1:
63
    rate = "25.00";
64
    break;
65
  case 3:
66
    rate = "29.97";
67
    break;
68
  default:
69
    rate = "(please send a bug report)";
70
    break;
71
  }
51
  
72
  fprintf(MSG_OUT," @ %s fps", rate);
52
  return S_OK;
73
}
53
}
74
54
75
static void nav_print_PCI_GI(pci_gi_t *pci_gi) {
55
btni_t *__get_current_button(dvdnav_t *self) {
76
  int32_t i;
56
  int button = 0;
77
57
78
  fprintf(MSG_OUT,"libdvdnav: pci_gi:\n");
58
  if(dvdnav_get_current_highlight(self, &button) != S_OK) {
79
  fprintf(MSG_OUT,"libdvdnav: nv_pck_lbn    0x%08x\n", pci_gi->nv_pck_lbn);
59
    printerrf("Unable to get information on current highlight.");
80
  fprintf(MSG_OUT,"libdvdnav: vobu_cat      0x%04x\n", pci_gi->vobu_cat);
60
    return NULL;
81
  fprintf(MSG_OUT,"libdvdnav: vobu_uop_ctl  0x%08x\n", *(uint32_t*)&pci_gi->vobu_uop_ctl);
61
  }
82
  fprintf(MSG_OUT,"libdvdnav: vobu_s_ptm    0x%08x\n", pci_gi->vobu_s_ptm);
62
#ifdef BUTTON_TESTING
83
  fprintf(MSG_OUT,"libdvdnav: vobu_e_ptm    0x%08x\n", pci_gi->vobu_e_ptm);
63
  navPrint_PCI(&(self->pci));
84
  fprintf(MSG_OUT,"libdvdnav: vobu_se_e_ptm 0x%08x\n", pci_gi->vobu_se_e_ptm);
64
#endif
85
  fprintf(MSG_OUT,"libdvdnav: e_eltm        ");
86
  print_time(&pci_gi->e_eltm);
87
  fprintf(MSG_OUT,"\n");
88
89
  fprintf(MSG_OUT,"libdvdnav: vobu_isrc     \"");
90
  for(i = 0; i < 32; i++) {
91
    char c = pci_gi->vobu_isrc[i];
92
    if((c >= ' ') && (c <= '~'))
93
      fprintf(MSG_OUT,"%c", c);
94
    else
95
      fprintf(MSG_OUT,".");
96
  }
65
  
97
  fprintf(MSG_OUT,"\"\n");
66
  return &(self->pci.hli.btnit[button-1]);
98
}
67
}
99
68
100
static void nav_print_NSML_AGLI(nsml_agli_t *nsml_agli) {
69
dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *self) {
101
  int32_t i, j = 0;
70
  btni_t *button_ptr;
71
  
72
  if(!self)
73
   return S_ERR;
102
74
103
  for(i = 0; i < 9; i++)
75
  if((button_ptr = __get_current_button(self)) == NULL) {
104
    j |= nsml_agli->nsml_agl_dsta[i];
105
  if(j == 0)
106
    return;
76
    return S_ERR;
77
  }
107
78
108
  fprintf(MSG_OUT,"libdvdnav: nsml_agli:\n");
79
  dvdnav_button_select(self, button_ptr->up);
109
  for(i = 0; i < 9; i++)
80
  
110
    if(nsml_agli->nsml_agl_dsta[i])
81
  return S_OK;
111
      fprintf(MSG_OUT,"libdvdnav: nsml_agl_c%d_dsta  0x%08x\n", i + 1,
112
             nsml_agli->nsml_agl_dsta[i]);
113
}
82
}
114
83
115
static void nav_print_HL_GI(hl_gi_t *hl_gi, int32_t *btngr_ns, int32_t *btn_ns) {
84
dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *self) {
85
  btni_t *button_ptr;
86
  
87
  if(!self)
88
   return S_ERR;
116
89
117
  if((hl_gi->hli_ss & 0x03) == 0)
90
  if((button_ptr = __get_current_button(self)) == NULL) {
118
    return;
91
    return S_ERR;
92
  }
119
93
120
  fprintf(MSG_OUT,"libdvdnav: hl_gi:\n");
94
  dvdnav_button_select(self, button_ptr->down);
121
  fprintf(MSG_OUT,"libdvdnav: hli_ss        0x%01x\n", hl_gi->hli_ss & 0x03);
95
  
122
  fprintf(MSG_OUT,"libdvdnav: hli_s_ptm     0x%08x\n", hl_gi->hli_s_ptm);
96
  return S_OK;
123
  fprintf(MSG_OUT,"libdvdnav: hli_e_ptm     0x%08x\n", hl_gi->hli_e_ptm);
124
  fprintf(MSG_OUT,"libdvdnav: btn_se_e_ptm  0x%08x\n", hl_gi->btn_se_e_ptm);
125
126
  *btngr_ns = hl_gi->btngr_ns;
127
  fprintf(MSG_OUT,"libdvdnav: btngr_ns      %d\n",  hl_gi->btngr_ns);
128
  fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty    0x%02x\n", 1, hl_gi->btngr1_dsp_ty);
129
  fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty    0x%02x\n", 2, hl_gi->btngr2_dsp_ty);
130
  fprintf(MSG_OUT,"libdvdnav: btngr%d_dsp_ty    0x%02x\n", 3, hl_gi->btngr3_dsp_ty);
131
132
  fprintf(MSG_OUT,"libdvdnav: btn_ofn       %d\n", hl_gi->btn_ofn);
133
  *btn_ns = hl_gi->btn_ns;
134
  fprintf(MSG_OUT,"libdvdnav: btn_ns        %d\n", hl_gi->btn_ns);
135
  fprintf(MSG_OUT,"libdvdnav: nsl_btn_ns    %d\n", hl_gi->nsl_btn_ns);
136
  fprintf(MSG_OUT,"libdvdnav: fosl_btnn     %d\n", hl_gi->fosl_btnn);
137
  fprintf(MSG_OUT,"libdvdnav: foac_btnn     %d\n", hl_gi->foac_btnn);
138
}
97
}
139
98
140
static void nav_print_BTN_COLIT(btn_colit_t *btn_colit) {
99
dvdnav_status_t dvdnav_right_button_select(dvdnav_t *self) {
141
  int32_t i, j;
100
  btni_t *button_ptr;
101
  
102
  if(!self)
103
   return S_ERR;
142
104
143
  j = 0;
105
  if((button_ptr = __get_current_button(self)) == NULL) {
144
  for(i = 0; i < 6; i++)
106
    printerr("Error fetching information on current button.");
145
    j |= btn_colit->btn_coli[i/2][i&1];
146
  if(j == 0)
147
    return;
107
    return S_ERR;
108
  }
148
109
149
  fprintf(MSG_OUT,"libdvdnav: btn_colit:\n");
110
  dvdnav_button_select(self, button_ptr->right);
150
  for(i = 0; i < 3; i++)
111
  
151
    for(j = 0; j < 2; j++)
112
  return S_OK;
152
      fprintf(MSG_OUT,"libdvdnav: btn_cqoli %d  %s_coli:  %08x\n",
153
             i, (j == 0) ? "sl" : "ac",
154
             btn_colit->btn_coli[i][j]);
155
}
113
}
156
114
157
static void nav_print_BTNIT(btni_t *btni_table, int32_t btngr_ns, int32_t btn_ns) {
115
dvdnav_status_t dvdnav_left_button_select(dvdnav_t *self) {
158
  int32_t i, j, k;
116
  btni_t *button_ptr;
117
  
118
  if(!self)
119
   return S_ERR;
159
120
160
  fprintf(MSG_OUT,"libdvdnav: btnit:\n");
121
  if((button_ptr = __get_current_button(self)) == NULL) {
161
  fprintf(MSG_OUT,"libdvdnav: btngr_ns: %i\n", btngr_ns);
162
  fprintf(MSG_OUT,"libdvdnav: btn_ns: %i\n", btn_ns);
163
164
  if(btngr_ns == 0)
165
    return;
122
    return S_ERR;
123
  }
166
124
167
  for(i = 0; i < btngr_ns; i++) {
125
  dvdnav_button_select(self, button_ptr->left);
168
    for(j = 0; j < (36 / btngr_ns); j++) {
126
  
169
      if(j < btn_ns) {
127
  return S_OK;
170
        btni_t *btni = &btni_table[(36 / btngr_ns) * i + j];
128
}
171
129
172
        fprintf(MSG_OUT,"libdvdnav: group %d btni %d:  ", i+1, j+1);
130
dvdnav_status_t dvdnav_button_activate(dvdnav_t *self) {
173
        fprintf(MSG_OUT,"btn_coln %d, auto_action_mode %d\n",
131
  int button;
174
               btni->btn_coln, btni->auto_action_mode);
132
  btni_t *button_ptr;
175
        fprintf(MSG_OUT,"libdvdnav: coords   (%d, %d) .. (%d, %d)\n",
133
  
176
               btni->x_start, btni->y_start, btni->x_end, btni->y_end);
134
  if(!self) 
135
   return S_ERR;
136
  pthread_mutex_lock(&self->vm_lock); 
177
137
178
        fprintf(MSG_OUT,"libdvdnav: up %d, ", btni->up);
138
  /* Precisely the same as selecting a button except we want
179
        fprintf(MSG_OUT,"down %d, ", btni->down);
139
   * a different palette */
180
        fprintf(MSG_OUT,"left %d, ", btni->left);
140
  if(dvdnav_get_current_highlight(self, &button) != S_OK) {
181
        fprintf(MSG_OUT,"right %d\n", btni->right);
141
    pthread_mutex_unlock(&self->vm_lock); 
182
        for(k = 0; k < 8; k++) {
142
    return S_ERR;
183
          fprintf(MSG_OUT, "libdvdnav: %02x ", btni->cmd.bytes[k]);
143
  }
184
        }
144
  if(dvdnav_button_select(self, button) != S_OK) {
185
        fprintf(MSG_OUT, "| ");
145
    pthread_mutex_unlock(&self->vm_lock); 
186
#ifdef TRACE
146
    return S_ERR;
187
        vm_print_mnemonic(&btni->cmd);
147
  }
148
  
149
  /* Now get the current button's info */
150
  if((button_ptr = __get_current_button(self)) == NULL) {
151
    printerr("Error fetching information on current button.");
152
    pthread_mutex_unlock(&self->vm_lock); 
153
    return S_ERR;
154
  }
155
156
  /* And set the palette */
157
  if(button_ptr->btn_coln != 0) {
158
    self->hli_clut = 
159
     self->pci.hli.btn_colit.btn_coli[button_ptr->btn_coln-1][1];
160
  } else {
161
    self->hli_clut = 0;
162
  }
163
164
  /* Finally, make the VM execute the appropriate code and
165
   * scedule a jump */
166
167
  if(vm_eval_cmd(self->vm, &(button_ptr->cmd)) == 1) {
168
    /* Cammand caused a jump */
169
    dvdnav_do_post_jump(self);
170
  }
171
  
172
  pthread_mutex_unlock(&self->vm_lock); 
173
  return S_OK;
174
}
175
176
dvdnav_status_t dvdnav_button_select(dvdnav_t *self, int button) {
177
  btni_t *button_ptr;
178
  
179
  if(!self) {
180
   printerrf("Unable to select button number %i as self state bad",
181
        button);
182
   return S_ERR;
183
  }
184
 
185
  printf("Button select %i\n", button); 
186
  
187
  /* Set the highlight SPRM if the passed button was valid*/
188
  if((button <= 0) || (button > self->pci.hli.hl_gi.btn_ns)) {
189
    printerrf("Unable to select button number %i as it doesn't exist",
190
        button);
191
    return S_ERR;
192
  }
193
  self->vm->state.HL_BTNN_REG = (button << 10);
194
195
  /* Now get the current button's info */
196
  if((button_ptr = __get_current_button(self)) == NULL) {
197
    printerr("Error fetching information on current button.");
198
    return S_ERR;
199
  }
200
201
  self->hli_bbox[0] = button_ptr->x_start;
202
  self->hli_bbox[1] = button_ptr->y_start;
203
  self->hli_bbox[2] = button_ptr->x_end;
204
  self->hli_bbox[3] = button_ptr->y_end;
205
  self->hli_state = 1; /* Selected */
206
207
  if(button_ptr->btn_coln != 0) {
208
    self->hli_clut = 
209
     self->pci.hli.btn_colit.btn_coli[button_ptr->btn_coln-1][0];
210
  } else {
211
    self->hli_clut = 0;
212
  }
213
  self->hli_pts = self->pci.hli.hl_gi.hli_s_ptm;
214
  self->hli_buttonN = button;
215
  self->highlight_changed = 1;
216
#ifdef BUTTON_TESTING
217
  printf("highlight.c:Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n",
218
         button_ptr->x_start, button_ptr->y_start,
219
         button_ptr->x_end, button_ptr->y_end,
220
         1,
221
         button);
188
#endif
222
#endif
189
        fprintf(MSG_OUT, "\n");
223
224
  return S_OK;
225
}
226
227
dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *self, 
228
                        int button) {
229
  /* A trivial function */
230
  if(dvdnav_button_select(self, button) != S_ERR) {
231
    return dvdnav_button_activate(self);
232
  }
233
  
234
  /* Should never get here without an error */
235
  return S_ERR;
236
}
237
238
dvdnav_status_t dvdnav_mouse_select(dvdnav_t *self, int x, int y) {
239
  int button, cur_button;
240
  
241
  /* FIXME: At the moment, the case of no button matchin (x,y) is
242
   * silently ignored, is this OK? */
243
  if(!self)
244
   return S_ERR;
245
246
  if(dvdnav_get_current_highlight(self, &cur_button) != S_OK) {
247
    return S_ERR;
248
  }
249
250
  /* Loop through each button */
251
  for(button=1; button <= self->pci.hli.hl_gi.btn_ns; button++) {
252
    btni_t *button_ptr = NULL;
253
254
    button_ptr = &(self->pci.hli.btnit[button-1]);
255
    if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) &&
256
       (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) {
257
      /* As an efficiency measure, only re-select the button
258
       * if it is different to the previously selected one. */
259
      if(button != cur_button) {
260
  dvdnav_button_select(self, button);
190
      }
261
      }
191
    }
262
    }
192
  }
263
  }
193
}
194
195
static void nav_print_HLI(hli_t *hli) {
196
  int32_t btngr_ns = 0, btn_ns = 0;
197
198
  fprintf(MSG_OUT,"libdvdnav: hli:\n");
199
  nav_print_HL_GI(&hli->hl_gi, & btngr_ns, & btn_ns);
200
  nav_print_BTN_COLIT(&hli->btn_colit);
201
  nav_print_BTNIT(hli->btnit, btngr_ns, btn_ns);
202
}
203
204
void nav_print_PCI(pci_t *pci) {
205
  fprintf(MSG_OUT,"libdvdnav: pci packet:\n");
206
  nav_print_PCI_GI(&pci->pci_gi);
207
  nav_print_NSML_AGLI(&pci->nsml_agli);
208
  nav_print_HLI(&pci->hli);
209
}
210
211
#endif
212
213
214
/* Highlighting API calls */
215
216
dvdnav_status_t dvdnav_get_current_highlight(dvdnav_t *this, int32_t *button) {
217
  /* Simply return the appropriate value based on the SPRM */
218
  if(((*button) = this->position_current.button) == -1)
219
    (*button) = this->vm->state.HL_BTNN_REG >> 10;
220
221
  return DVDNAV_STATUS_OK;
222
}
223
224
static btni_t *get_current_button(dvdnav_t *this, pci_t *pci) {
225
  int32_t button = 0;
226
227
  if(!pci->hli.hl_gi.hli_ss) {
228
    printerr("Not in a menu.");
229
    return NULL;
230
  }
264
  
231
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
265
  return S_OK;
232
    printerr("This NAV has already been left.");
233
    return NULL;
234
  }
235
236
  button = this->vm->state.HL_BTNN_REG >> 10;
237
#ifdef BUTTON_TESTING
238
  nav_print_PCI(pci);
239
#endif
240
241
  return &(pci->hli.btnit[button-1]);
242
}
266
}
243
267
244
static dvdnav_status_t button_auto_action(dvdnav_t *this, pci_t *pci) {
268
dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *self, int x, int y) {
245
  if (get_current_button(this, pci)->auto_action_mode)
246
    return dvdnav_button_activate(this, pci);
247
  return DVDNAV_STATUS_OK;
248
}
249
250
dvdnav_status_t dvdnav_upper_button_select(dvdnav_t *this, pci_t *pci) {
251
  btni_t *button_ptr;
252
253
  if(!(button_ptr = get_current_button(this, pci)))
254
    return DVDNAV_STATUS_ERR;
255
256
  dvdnav_button_select(this, pci, button_ptr->up);
257
  return button_auto_action(this, pci);
258
}
259
260
dvdnav_status_t dvdnav_lower_button_select(dvdnav_t *this, pci_t *pci) {
261
  btni_t *button_ptr;
262
263
  if(!(button_ptr = get_current_button(this, pci)))
264
    return DVDNAV_STATUS_ERR;
265
266
  dvdnav_button_select(this, pci, button_ptr->down);
267
  return button_auto_action(this, pci);
268
}
269
270
dvdnav_status_t dvdnav_right_button_select(dvdnav_t *this, pci_t *pci) {
271
  btni_t *button_ptr;
272
273
  if(!(button_ptr = get_current_button(this, pci)))
274
    return DVDNAV_STATUS_ERR;
275
276
  dvdnav_button_select(this, pci, button_ptr->right);
277
  return button_auto_action(this, pci);
278
}
279
280
dvdnav_status_t dvdnav_left_button_select(dvdnav_t *this, pci_t *pci) {
281
  btni_t *button_ptr;
282
283
  if(!(button_ptr = get_current_button(this, pci)))
284
    return DVDNAV_STATUS_ERR;
285
286
  dvdnav_button_select(this, pci, button_ptr->left);
287
  return button_auto_action(this, pci);
288
}
289
290
dvdnav_status_t dvdnav_get_highlight_area(pci_t *nav_pci , int32_t button, int32_t mode,
291
                    dvdnav_highlight_area_t *highlight) {
292
  btni_t *button_ptr;
293
294
#ifdef BUTTON_TESTING
295
  fprintf(MSG_OUT, "libdvdnav: Button get_highlight_area %i\n", button);
296
#endif
297
298
  if(!nav_pci->hli.hl_gi.hli_ss)
299
    return DVDNAV_STATUS_ERR;
300
  if((button <= 0) || (button > nav_pci->hli.hl_gi.btn_ns))
301
    return DVDNAV_STATUS_ERR;
302
303
304
  button_ptr = &nav_pci->hli.btnit[button-1];
305
306
  highlight->sx = button_ptr->x_start;
307
  highlight->sy = button_ptr->y_start;
308
  highlight->ex = button_ptr->x_end;
309
  highlight->ey = button_ptr->y_end;
310
  if(button_ptr->btn_coln != 0) {
311
    highlight->palette = nav_pci->hli.btn_colit.btn_coli[button_ptr->btn_coln-1][mode];
312
  } else {
313
    highlight->palette = 0;
314
  }
315
  highlight->pts = nav_pci->hli.hl_gi.hli_s_ptm;
316
  highlight->buttonN = button;
317
#ifdef BUTTON_TESTING
318
  fprintf(MSG_OUT, "libdvdnav: highlight: Highlight area is (%u,%u)-(%u,%u), display = %i, button = %u\n",
319
               button_ptr->x_start, button_ptr->y_start,
320
               button_ptr->x_end, button_ptr->y_end,
321
               1,
322
               button);
323
#endif
324
325
  return DVDNAV_STATUS_OK;
326
}
327
328
dvdnav_status_t dvdnav_button_activate(dvdnav_t *this, pci_t *pci) {
329
  int32_t button;
330
  btni_t *button_ptr = NULL;
331
332
  if(!pci->hli.hl_gi.hli_ss) {
333
    printerr("Not in a menu.");
334
    return DVDNAV_STATUS_ERR;
335
  }
336
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
337
    printerr("This NAV has already been left.");
338
    return DVDNAV_STATUS_ERR;
339
  }
340
  pthread_mutex_lock(&this->vm_lock);
341
342
  button = this->vm->state.HL_BTNN_REG >> 10;
343
344
  if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
345
    /* Special code to handle still menus with no buttons.
346
     * The navigation is expected to report to the application that a STILL is
347
     * underway. In turn, the application is supposed to report to the user
348
     * that the playback is paused. The user is then expected to undo the pause,
349
     * ie: hit play. At that point, the navigation should release the still and
350
     * go to the next Cell.
351
     * Explanation by Mathieu Lacage <mathieu_lacage@realmagic.fr>
352
     * Code added by jcdutton.
353
     */
354
    if (this->position_current.still != 0) {
355
      /* In still, but no buttons. */
356
      vm_get_next_cell(this->vm);
357
      this->position_current.still = 0;
358
      this->sync_wait = 0;
359
      this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
360
      pthread_mutex_unlock(&this->vm_lock);
361
      /* clear error message */
362
      printerr("");
363
      return DVDNAV_STATUS_OK;
364
    }
365
    pthread_mutex_unlock(&this->vm_lock);
366
    return DVDNAV_STATUS_ERR;
367
  }
368
369
  button_ptr = get_current_button(this, pci);
370
  /* Finally, make the VM execute the appropriate code and probably
371
   * scedule a jump */
372
#ifdef BUTTON_TESTING
373
  fprintf(MSG_OUT, "libdvdnav: Evaluating Button Activation commands.\n");
374
#endif
375
  if(vm_exec_cmd(this->vm, &(button_ptr->cmd)) == 1) {
376
    /* Command caused a jump */
377
    this->vm->hop_channel++;
378
    this->position_current.still = 0;
379
    this->last_cmd_nav_lbn = pci->pci_gi.nv_pck_lbn;
380
  }
381
382
  pthread_mutex_unlock(&this->vm_lock);
383
  return DVDNAV_STATUS_OK;
384
}
385
386
dvdnav_status_t dvdnav_button_activate_cmd(dvdnav_t *this, int32_t button, vm_cmd_t *cmd)
387
{
388
  pthread_mutex_lock(&this->vm_lock);
389
  /* make the VM execute the appropriate code and probably
390
   * schedule a jump */
391
#ifdef BUTTON_TESTING
392
  fprintf(MSG_OUT, "libdvdnav: dvdnav_button_activate_cmd: Evaluating Button Activation commands.\n");
393
#endif
394
  if(button > 0) {
395
    this->vm->state.HL_BTNN_REG = (button << 10);
396
    if(vm_exec_cmd(this->vm, cmd) == 1) {
397
      /* Command caused a jump */
398
      this->vm->hop_channel++;
399
    }
400
  }
401
  /* Always remove still, because some still menus have no buttons. */
402
  this->position_current.still = 0;
403
  this->sync_wait = 0;
404
  pthread_mutex_unlock(&this->vm_lock);
405
  return DVDNAV_STATUS_OK;
406
}
407
408
dvdnav_status_t dvdnav_button_select(dvdnav_t *this, pci_t *pci, int32_t button) {
409
  if(!pci->hli.hl_gi.hli_ss) {
410
    printerr("Not in a menu.");
411
    return DVDNAV_STATUS_ERR;
412
  }
413
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
414
    printerr("This NAV has already been left.");
415
    return DVDNAV_STATUS_ERR;
416
  }
417
418
#ifdef BUTTON_TESTING
419
  fprintf(MSG_OUT, "libdvdnav: Button select %i\n", button);
420
#endif
421
422
  if((button <= 0) || (button > pci->hli.hl_gi.btn_ns)) {
423
    printerr("Button does not exist.");
424
    return DVDNAV_STATUS_ERR;
425
  }
426
427
  this->vm->state.HL_BTNN_REG = (button << 10);
428
  this->position_current.button = -1; /* Force Highligh change */
429
430
  return DVDNAV_STATUS_OK;
431
}
432
433
dvdnav_status_t dvdnav_button_select_and_activate(dvdnav_t *this, pci_t *pci,
434
                        int32_t button) {
435
  /* A trivial function */
269
  /* A trivial function */
436
  if(dvdnav_button_select(this, pci, button) != DVDNAV_STATUS_ERR)
270
  if(dvdnav_mouse_select(self, x,y) != S_ERR) {
437
    return dvdnav_button_activate(this, pci);
271
    return dvdnav_button_activate(self);
438
  return DVDNAV_STATUS_ERR;
272
  }
439
}
440
441
dvdnav_status_t dvdnav_mouse_select(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
442
  int32_t button, cur_button;
443
  int32_t best,dist,d;
444
  int32_t mx,my,dx,dy;
445
446
  if(!pci->hli.hl_gi.hli_ss) {
447
    printerr("Not in a menu.");
448
    return DVDNAV_STATUS_ERR;
449
  }
273
  
450
  if(this->last_cmd_nav_lbn == pci->pci_gi.nv_pck_lbn) {
274
  /* Should never get here without an error */
451
    printerr("This NAV has already been left.");
275
  return S_ERR;
452
    return DVDNAV_STATUS_ERR;
453
  }
454
455
  cur_button = this->vm->state.HL_BTNN_REG >> 10;
456
457
  best = 0;
458
  dist = 0x08000000; /* >> than  (720*720)+(567*567); */
459
460
  /* Loop through all buttons */
461
  for(button = 1; button <= pci->hli.hl_gi.btn_ns; button++) {
462
    btni_t *button_ptr = &(pci->hli.btnit[button-1]);
463
464
    if((x >= button_ptr->x_start) && (x <= button_ptr->x_end) &&
465
       (y >= button_ptr->y_start) && (y <= button_ptr->y_end)) {
466
      mx = (button_ptr->x_start + button_ptr->x_end)/2;
467
      my = (button_ptr->y_start + button_ptr->y_end)/2;
468
      dx = mx - x;
469
      dy = my - y;
470
      d = (dx*dx) + (dy*dy);
471
      /* If the mouse is within the button and the mouse is closer
472
       * to the center of this button then it is the best choice. */
473
      if(d < dist) {
474
        dist = d;
475
        best = button;
476
      }
477
    }
478
  }
479
  /* As an efficiency measure, only re-select the button
480
   * if it is different to the previously selected one. */
481
  if (best != 0 && best != cur_button)
482
    dvdnav_button_select(this, pci, best);
483
484
  /* return DVDNAV_STATUS_OK only if we actually found a matching button */
485
  return best ? DVDNAV_STATUS_OK : DVDNAV_STATUS_ERR;
486
}
276
}
487
277
488
dvdnav_status_t dvdnav_mouse_activate(dvdnav_t *this, pci_t *pci, int32_t x, int32_t y) {
489
  /* A trivial function */
490
  if(dvdnav_mouse_select(this, pci, x,y) != DVDNAV_STATUS_ERR)
491
    return dvdnav_button_activate(this, pci);
492
  return DVDNAV_STATUS_ERR;
493
}