1 package org.coolreader.crengine; 2 3 import java.util.ArrayList; 4 5 import org.coolreader.CoolReader; 6 import org.coolreader.R; 7 8 import android.graphics.Bitmap; 9 import android.content.res.TypedArray; 10 import android.graphics.Canvas; 11 import android.graphics.ColorMatrix; 12 import android.graphics.ColorMatrixColorFilter; 13 import android.graphics.Paint; 14 import android.graphics.Rect; 15 import android.graphics.drawable.Drawable; 16 import android.view.ContextMenu; 17 import android.view.Gravity; 18 import android.view.KeyEvent; 19 import android.view.LayoutInflater; 20 import android.view.MotionEvent; 21 import android.view.View; 22 import android.view.ViewGroup; 23 import android.view.WindowManager; 24 import android.widget.ImageButton; 25 import android.widget.ImageView; 26 import android.widget.LinearLayout; 27 import android.widget.PopupWindow; 28 import android.widget.ScrollView; 29 import android.widget.TextView; 30 31 public class CRToolBar extends ViewGroup { 32 private static final Logger log = L.create("tb"); 33 34 final private BaseActivity activity; 35 private ArrayList<ReaderAction> actions = new ArrayList<>(); 36 private ArrayList<ReaderAction> iconActions = new ArrayList<>(); 37 private int buttonHeight; 38 private int buttonWidth; 39 private int itemHeight; // multiline mode, line height 40 private int visibleButtonCount; 41 private int visibleNonButtonCount; 42 private boolean isVertical; 43 private boolean isMultiline; 44 final private int preferredItemHeight; 45 private int BUTTON_SPACING = 4; 46 private int BAR_SPACING = 4; 47 private int buttonAlpha = 0xFF; 48 private int windowDividerHeight = 0; // for popup window, height of divider below buttons 49 private ImageButton overflowButton; 50 private LayoutInflater inflater; 51 private PopupWindow popup; 52 private int popupLocation = Settings.VIEWER_TOOLBAR_BOTTOM; 53 private int maxMultilineLines = 3; 54 private int optionAppearance = 0; 55 private float toolbarScale = 1.0f; 56 private boolean grayIcons = false; 57 setPopup(PopupWindow popup, int popupLocation)58 private void setPopup(PopupWindow popup, int popupLocation) { 59 this.popup = popup; 60 this.popupLocation = popupLocation; 61 } 62 63 private ArrayList<ReaderAction> itemsOverflow = new ArrayList<>(); 64 setButtonAlpha(int alpha)65 public void setButtonAlpha(int alpha) { 66 this.buttonAlpha = alpha; 67 if (isShown()) { 68 requestLayout(); 69 invalidate(); 70 } 71 } 72 setVertical(boolean vertical)73 public void setVertical(boolean vertical) { 74 this.isVertical = vertical; 75 if (isVertical) { 76 //setPadding(BUTTON_SPACING, BUTTON_SPACING, BAR_SPACING, BUTTON_SPACING); 77 setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT)); 78 } else { 79 //setPadding(BUTTON_SPACING, BAR_SPACING, BUTTON_SPACING, BUTTON_SPACING); 80 setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); 81 } 82 } isVertical()83 public boolean isVertical() { 84 return this.isVertical; 85 } 86 CRToolBar(BaseActivity context)87 public CRToolBar(BaseActivity context) { 88 super(context); 89 this.activity = context; 90 this.preferredItemHeight = context.getPreferredItemHeight(); 91 } 92 inflateItem(ReaderAction action)93 private LinearLayout inflateItem(ReaderAction action) { 94 final LinearLayout view = (LinearLayout)inflater.inflate(R.layout.popup_toolbar_item, null); 95 ImageView icon = view.findViewById(R.id.action_icon); 96 TextView label = view.findViewById(R.id.action_label); 97 icon.setImageResource(action != null ? action.iconId : Utils.resolveResourceIdByAttr(activity, R.attr.cr3_button_more_drawable, R.drawable.cr3_button_more)); 98 //icon.setMinimumHeight(buttonHeight); 99 icon.setMinimumWidth(buttonWidth); 100 Utils.setContentDescription(icon, activity.getString(action != null ? action.nameId : R.string.btn_toolbar_more)); 101 label.setText(action != null ? action.nameId : R.string.btn_toolbar_more); 102 view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 103 return view; 104 } 105 CRToolBar(BaseActivity context, ArrayList<ReaderAction> actions, boolean multiline)106 public CRToolBar(BaseActivity context, ArrayList<ReaderAction> actions, boolean multiline) { 107 super(context); 108 this.activity = context; 109 this.actions = actions; 110 this.isMultiline = multiline; 111 this.preferredItemHeight = activity.getPreferredItemHeight(); //context.getPreferredItemHeight(); 112 this.inflater = LayoutInflater.from(activity); 113 this.windowDividerHeight = multiline ? 8 : 0; 114 context.getWindow().getAttributes(); 115 if (context.isSmartphone()) { 116 BUTTON_SPACING = 3; 117 BAR_SPACING = 0; //3; 118 } else { 119 BUTTON_SPACING = preferredItemHeight / 20; 120 BAR_SPACING = 0; //preferredItemHeight / 20; 121 } 122 calcLayout(); 123 L.d("CRToolBar preferredItemHeight=" + preferredItemHeight + " buttonWidth=" + buttonWidth + " buttonHeight=" + buttonHeight + " buttonSpacing=" + BUTTON_SPACING); 124 } 125 calcLayout()126 private void calcLayout() { 127 if (activity instanceof CoolReader) { 128 //Properties settings = ((CoolReader)activity).getReaderView().getSettings(); 129 //this.optionAppearance = settings.getInt(ReaderView.PROP_TOOLBAR_APPEARANCE, 0); 130 optionAppearance = Integer.parseInt(((CoolReader)activity).getToolbarAppearance()); 131 toolbarScale = 1.0f; 132 grayIcons = false; 133 switch (optionAppearance) { 134 case Settings.VIEWER_TOOLBAR_100: // 0 135 case Settings.VIEWER_TOOLBAR_100_gray: // 1 136 toolbarScale = 1.0f; 137 break; 138 case Settings.VIEWER_TOOLBAR_75: // 2 139 toolbarScale = 0.75f; 140 break; 141 case Settings.VIEWER_TOOLBAR_75_gray: // 3 142 toolbarScale = 0.75f; 143 grayIcons = true; 144 break; 145 case Settings.VIEWER_TOOLBAR_50: // 4 146 toolbarScale = 0.5f; 147 break; 148 case Settings.VIEWER_TOOLBAR_50_gray: // 5 149 toolbarScale = 0.5f; 150 grayIcons = true; 151 break; 152 } 153 } 154 int sz = (int)((float)preferredItemHeight * toolbarScale); //(activity.isSmartphone() ? preferredItemHeight * 6 / 10 - BUTTON_SPACING : preferredItemHeight); 155 buttonWidth = buttonHeight = sz - BUTTON_SPACING; 156 if (isMultiline) 157 buttonHeight = sz / 2; 158 for (int i=0; i<actions.size(); i++) { 159 ReaderAction item = actions.get(i); 160 int iconId = item.iconId; 161 if (iconId == 0) { 162 itemsOverflow.add(item); 163 visibleNonButtonCount++; 164 continue; 165 } 166 iconActions.add(item); 167 Drawable d = activity.getResources().getDrawable(iconId); 168 visibleButtonCount++; 169 int w = d.getIntrinsicWidth();// * dpi / 160; 170 int h = d.getIntrinsicHeight();// * dpi / 160; 171 if (buttonWidth < w) { 172 buttonWidth = w; 173 } 174 if (buttonHeight < h) { 175 buttonHeight = h; 176 } 177 } 178 if (isMultiline) { 179 LinearLayout item = inflateItem(iconActions.get(0)); 180 itemHeight = item.getMeasuredHeight() + BUTTON_SPACING; 181 } 182 } 183 184 private OnActionHandler onActionHandler; 185 setOnActionHandler(OnActionHandler handler)186 public void setOnActionHandler(OnActionHandler handler) { 187 this.onActionHandler = handler; 188 } 189 190 private OnOverflowHandler onOverflowHandler; 191 setOnOverflowHandler(OnOverflowHandler handler)192 public void setOnOverflowHandler(OnOverflowHandler handler) { 193 this.onOverflowHandler = handler; 194 } 195 196 public interface OnActionHandler { onActionSelected(ReaderAction item)197 boolean onActionSelected(ReaderAction item); 198 } 199 public interface OnOverflowHandler { onOverflowActions(ArrayList<ReaderAction> actions)200 boolean onOverflowActions(ArrayList<ReaderAction> actions); 201 } 202 203 @Override onCreateContextMenu(ContextMenu menu)204 protected void onCreateContextMenu(ContextMenu menu) { 205 int order = 0; 206 for (ReaderAction action : itemsOverflow) { 207 menu.add(0, action.menuItemId, order++, action.nameId); 208 } 209 } 210 allActionsHaveIcon(ArrayList<ReaderAction> list)211 private static boolean allActionsHaveIcon(ArrayList<ReaderAction> list) { 212 for (ReaderAction item : list) { 213 if (item.iconId == 0) 214 return false; 215 } 216 return true; 217 } 218 showOverflowMenu()219 public void showOverflowMenu() { 220 if (itemsOverflow.size() > 0) { 221 if (onOverflowHandler != null) 222 onOverflowHandler.onOverflowActions(itemsOverflow); 223 else { 224 if (!isMultiline && visibleNonButtonCount == 0) { 225 showPopup(activity, activity.getContentView(), actions, onActionHandler, onOverflowHandler, actions.size(), Settings.VIEWER_TOOLBAR_TOP); 226 } else { 227 if (allActionsHaveIcon(itemsOverflow)) { 228 if (popup != null) 229 popup.dismiss(); 230 showPopup(activity, activity.getContentView(), itemsOverflow, onActionHandler, onOverflowHandler, actions.size(), isMultiline ? popupLocation : Settings.VIEWER_TOOLBAR_BOTTOM); 231 } else 232 activity.showActionsPopupMenu(itemsOverflow, onActionHandler); 233 } 234 } 235 // PopupMenu menu = new PopupMenu(activity, this); 236 // int order = 0; 237 // for (ReaderAction action : itemsOverflow) { 238 // menu.getMenu().add(0, action.menuItemId, order++, action.nameId); 239 // } 240 // menu.show(); 241 // showContextMenuForChild(overflowButton); 242 } 243 } 244 245 // private void onMoreButtonClick() { 246 // showOverflowMenu(); 247 // } 248 onButtonClick(ReaderAction item)249 private void onButtonClick(ReaderAction item) { 250 if (onActionHandler != null) 251 onActionHandler.onActionSelected(item); 252 } 253 setButtonImageResource(ImageButton ib, int resId)254 private void setButtonImageResource(ImageButton ib, int resId) { 255 if (optionAppearance == Settings.VIEWER_TOOLBAR_100) { 256 ib.setImageResource(resId); 257 return; 258 } 259 Drawable dr = getResources().getDrawable(resId); 260 int iWidth = dr.getIntrinsicWidth(); 261 iWidth = (int) ((float) iWidth * this.toolbarScale); 262 int iHeight = dr.getIntrinsicHeight(); 263 iHeight = (int) ((float) iHeight * this.toolbarScale); 264 Bitmap bitmap = Bitmap.createBitmap(iWidth, iHeight, Bitmap.Config.ARGB_8888); 265 Canvas canvas = new Canvas(bitmap); 266 dr.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 267 dr.draw(canvas); 268 if (this.grayIcons) { 269 Bitmap bmpGrayscale = Bitmap.createBitmap(iWidth, iHeight, Bitmap.Config.ARGB_8888); 270 Canvas c = new Canvas(bmpGrayscale); 271 Paint paint = new Paint(); 272 ColorMatrix cm = new ColorMatrix(); 273 cm.setSaturation(0); 274 ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm); 275 paint.setColorFilter(f); 276 c.drawBitmap(bitmap, 0, 0, paint); 277 ib.setImageBitmap(bmpGrayscale); 278 } else { 279 ib.setImageBitmap(bitmap); 280 } 281 } 282 addButton(Rect rect, final ReaderAction item, boolean left)283 private ImageButton addButton(Rect rect, final ReaderAction item, boolean left) { 284 Rect rc = new Rect(rect); 285 if (isVertical) { 286 if (left) { 287 rc.bottom = rc.top + buttonHeight; 288 rect.top += buttonHeight + BUTTON_SPACING; 289 } else { 290 rc.top = rc.bottom - buttonHeight; 291 rect.bottom -= buttonHeight + BUTTON_SPACING; 292 } 293 } else { 294 if (left) { 295 rc.right = rc.left + buttonWidth; 296 rect.left += buttonWidth + BUTTON_SPACING; 297 } else { 298 rc.left = rc.right - buttonWidth; 299 rect.right -= buttonWidth + BUTTON_SPACING; 300 } 301 } 302 if (rc.isEmpty()) 303 return null; 304 ImageButton ib = new ImageButton(getContext()); 305 if (item != null) { 306 setButtonImageResource(ib,item.iconId); 307 Utils.setContentDescription(ib, getContext().getString(item.nameId)); 308 ib.setTag(item); 309 } else { 310 setButtonImageResource(ib,Utils.resolveResourceIdByAttr(activity, R.attr.cr3_button_more_drawable, R.drawable.cr3_button_more)); 311 Utils.setContentDescription(ib, getContext().getString(R.string.btn_toolbar_more)); 312 } 313 TypedArray a = activity.getTheme().obtainStyledAttributes( new int[] { R.attr.cr3_toolbar_button_background_drawable } ); 314 int cr3_toolbar_button_background = a.getResourceId(0, 0); 315 a.recycle(); 316 if (0 == cr3_toolbar_button_background) 317 cr3_toolbar_button_background = R.drawable.cr3_toolbar_button_background; 318 ib.setBackgroundResource(cr3_toolbar_button_background); 319 ib.layout(rc.left, rc.top, rc.right, rc.bottom); 320 if (item == null) 321 overflowButton = ib; 322 ib.setOnClickListener(v -> { 323 if (item != null) 324 onButtonClick(item); 325 else 326 showOverflowMenu(); 327 }); 328 ib.setAlpha(nightMode ? 0x60 : buttonAlpha); 329 addView(ib); 330 return ib; 331 } 332 333 private Rect layoutRect = new Rect(); 334 private Rect layoutLineRect = new Rect(); 335 private Rect layoutItemRect = new Rect(); 336 @Override onLayout(boolean changed, int left, int top, int right, int bottom)337 protected void onLayout(boolean changed, int left, int top, int right, 338 int bottom) { 339 right -= left; 340 bottom -= top; 341 left = top = 0; 342 //calcLayout(); 343 removeAllViews(); 344 overflowButton = null; 345 346 if (isMultiline) { 347 itemsOverflow.clear(); 348 int lastButtonIndex = -1; 349 350 int lineCount = calcLineCount(right); 351 int btnCount = iconActions.size() + (visibleNonButtonCount > 0 ? 1 : 0); 352 int buttonsPerLine = (btnCount + lineCount - 1) / lineCount; 353 354 int y0 = 0; 355 if (popupLocation == Settings.VIEWER_TOOLBAR_BOTTOM) { 356 View separator = new View(activity); 357 separator.setBackgroundResource(activity.getCurrentTheme().getBrowserStatusBackground()); 358 addView(separator); 359 separator.layout(left, top, right, top + windowDividerHeight); 360 y0 = windowDividerHeight + 4; 361 } 362 363 364 // ScrollView scroll = new ScrollView(activity); 365 // scroll.setLayoutParams(new LayoutParams(right, bottom)); 366 // AbsoluteLayout content = new AbsoluteLayout(activity); 367 368 layoutRect.set(left + getPaddingLeft() + BUTTON_SPACING, top + getPaddingTop() + BUTTON_SPACING, right - getPaddingRight() - BUTTON_SPACING, bottom - getPaddingBottom() - BUTTON_SPACING - y0); 369 int lineH = itemHeight; //rect.height() / lineCount; 370 int spacing = 0; 371 int maxLines = bottom / lineH; 372 if (maxLines > maxMultilineLines) 373 maxLines = maxMultilineLines; 374 for (int currentLine = 0; currentLine < lineCount && currentLine < maxLines; currentLine++) { 375 int startBtn = currentLine * buttonsPerLine; 376 int endBtn = (currentLine + 1) * buttonsPerLine; 377 if (endBtn > btnCount) 378 endBtn = btnCount; 379 int currentLineButtons = endBtn - startBtn; 380 layoutLineRect.set(layoutRect); 381 layoutLineRect.top += currentLine * lineH + spacing + y0; 382 layoutLineRect.bottom = layoutLineRect.top + lineH - spacing; 383 int itemWidth = layoutLineRect.width() / currentLineButtons; 384 for (int i = 0; i < currentLineButtons; i++) { 385 layoutItemRect.set(layoutLineRect); 386 layoutItemRect.left += i * itemWidth + spacing; 387 layoutItemRect.right = layoutItemRect.left + itemWidth - spacing; 388 final ReaderAction action = (visibleNonButtonCount > 0 && i + startBtn == iconActions.size()) || (lineCount > maxLines && currentLine == maxLines - 1 && i == currentLineButtons - 1) ? null : iconActions.get(startBtn + i); 389 if (action != null) 390 lastButtonIndex = startBtn + i; 391 log.v("item=" + layoutItemRect); 392 LinearLayout item = inflateItem(action); 393 //item.setLayoutParams(new LinearLayout.LayoutParams(itemRect.width(), itemRect.height())); 394 item.measure(MeasureSpec.makeMeasureSpec(layoutItemRect.width(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(layoutItemRect.height(), MeasureSpec.EXACTLY)); 395 item.layout(layoutItemRect.left, layoutItemRect.top, layoutItemRect.right, layoutItemRect.bottom); 396 //item.forceLayout(); 397 addView(item); 398 item.setOnClickListener(v -> { 399 if (action != null) 400 onButtonClick(action); 401 else 402 showOverflowMenu(); 403 }); 404 } 405 // addView(scroll); 406 } 407 if (popupLocation != Settings.VIEWER_TOOLBAR_BOTTOM) { 408 View separator = new View(activity); 409 separator.setBackgroundResource(activity.getCurrentTheme().getBrowserStatusBackground()); 410 addView(separator); 411 separator.layout(left, bottom - windowDividerHeight, right, bottom); 412 } 413 //popup. 414 if (lastButtonIndex > 0) 415 for (int i=lastButtonIndex + 1; i < actions.size(); i++) 416 itemsOverflow.add(actions.get(i)); 417 return; 418 } 419 420 // View divider = new View(getContext()); 421 // addView(divider); 422 // if (isVertical()) { 423 // divider.setBackgroundResource(R.drawable.divider_light_vertical_tiled); 424 // divider.layout(right - 8, top, right, bottom); 425 // } else { 426 // divider.setBackgroundResource(R.drawable.divider_light_tiled); 427 // divider.layout(left, bottom - 8, right, bottom); 428 // } 429 430 visibleButtonCount = 0; 431 for (int i=0; i<actions.size(); i++) { 432 if (actions.get(i).iconId != 0) 433 visibleButtonCount++; 434 } 435 436 437 Rect rect = new Rect(left + getPaddingLeft() + BUTTON_SPACING, top + getPaddingTop() + BUTTON_SPACING, right - getPaddingRight() - BUTTON_SPACING, bottom - getPaddingBottom() - BUTTON_SPACING); 438 if (rect.isEmpty()) 439 return; 440 ArrayList<ReaderAction> itemsToShow = new ArrayList<ReaderAction>(); 441 itemsOverflow.clear(); 442 int maxButtonCount = 1; 443 if (isVertical) { 444 rect.right -= BAR_SPACING; 445 int maxHeight = bottom - top - getPaddingTop() - getPaddingBottom() + BUTTON_SPACING; 446 maxButtonCount = maxHeight / (buttonHeight + BUTTON_SPACING); 447 } else { 448 rect.bottom -= BAR_SPACING; 449 int maxWidth = right - left - getPaddingLeft() - getPaddingRight() + BUTTON_SPACING; 450 maxButtonCount = maxWidth / (buttonWidth + BUTTON_SPACING); 451 } 452 int count = 0; 453 boolean addEllipsis = visibleButtonCount > maxButtonCount || visibleNonButtonCount > 0; 454 if (addEllipsis) { 455 addButton(rect, null, false); 456 maxButtonCount--; 457 } 458 for (int i = 0; i < actions.size(); i++) { 459 ReaderAction item = actions.get(i); 460 if (count >= maxButtonCount) { 461 itemsOverflow.add(item); 462 continue; 463 } 464 if (item.iconId == 0) { 465 itemsOverflow.add(item); 466 continue; 467 } 468 itemsToShow.add(item); 469 count++; 470 addButton(rect, item, true); 471 } 472 } 473 474 @Override onMeasure(int widthMeasureSpec, int heightMeasureSpec)475 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 476 // int widthMode = MeasureSpec.getMode(widthMeasureSpec); 477 // if (widthMode != MeasureSpec.EXACTLY) { 478 // throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 479 // "with android:layout_width=\"match_parent\" (or fill_parent)"); 480 // } 481 482 // int heightMode = MeasureSpec.getMode(heightMeasureSpec); 483 // if (heightMode != MeasureSpec.AT_MOST) { 484 // throw new IllegalStateException(getClass().getSimpleName() + " can only be used " + 485 // "with android:layout_height=\"wrap_content\""); 486 // } 487 488 if (isVertical) { 489 int contentHeight = MeasureSpec.getSize(heightMeasureSpec); 490 int maxWidth = buttonWidth + BUTTON_SPACING + BUTTON_SPACING + BAR_SPACING + getPaddingLeft() + getPaddingRight(); 491 setMeasuredDimension(maxWidth, contentHeight); 492 } else { 493 int contentWidth = MeasureSpec.getSize(widthMeasureSpec); 494 if (isMultiline) { 495 int contentHeight = MeasureSpec.getSize(heightMeasureSpec); 496 int lineCount = calcLineCount(contentWidth); 497 if (lineCount > maxMultilineLines) 498 lineCount = maxMultilineLines; 499 int h = lineCount * itemHeight + BAR_SPACING + BAR_SPACING + windowDividerHeight + 4; 500 // if (h > contentHeight - itemHeight) 501 // h = contentHeight - itemHeight; 502 setMeasuredDimension(contentWidth, h); 503 } else { 504 setMeasuredDimension(contentWidth, buttonHeight + BUTTON_SPACING * 2 + BAR_SPACING); 505 } 506 } 507 } 508 calcLineCount(int contentWidth)509 protected int calcLineCount(int contentWidth) { 510 if (!isMultiline) 511 return 1; 512 int lineCount = 1; 513 int btnCount = iconActions.size() + (visibleNonButtonCount > 0 ? 1 : 0); 514 int minLineItemCount = 3; 515 int maxLineItemCount = contentWidth / (preferredItemHeight * 3 / 2); 516 if (maxLineItemCount < minLineItemCount) 517 maxLineItemCount = minLineItemCount; 518 519 for (;;) { 520 if (btnCount <= maxLineItemCount * lineCount) 521 return lineCount; 522 lineCount++; 523 } 524 } 525 526 @Override onSizeChanged(int w, int h, int oldw, int oldh)527 protected void onSizeChanged(int w, int h, int oldw, int oldh) { 528 super.onSizeChanged(w, h, oldw, oldh); 529 log.v("CRToolBar.onSizeChanged(" + w + ", " + h + ")"); 530 } 531 532 533 534 @Override onDraw(Canvas canvas)535 protected void onDraw(Canvas canvas) { 536 log.v("CRToolBar.onDraw(" + getWidth() + ", " + getHeight() + ")"); 537 super.onDraw(canvas); 538 } showAsPopup(View anchor, OnActionHandler onActionHandler, OnOverflowHandler onOverflowHandler)539 public PopupWindow showAsPopup(View anchor, OnActionHandler onActionHandler, OnOverflowHandler onOverflowHandler) { 540 return showPopup(activity, anchor, actions, onActionHandler, onOverflowHandler, 3, Settings.VIEWER_TOOLBAR_BOTTOM); 541 } 542 setMaxLines(int maxLines)543 private void setMaxLines(int maxLines) { 544 this.maxMultilineLines = maxLines; 545 } 546 showPopup(BaseActivity context, View anchor, ArrayList<ReaderAction> actions, final OnActionHandler onActionHandler, final OnOverflowHandler onOverflowHandler, int maxLines, int popupLocation)547 public static PopupWindow showPopup(BaseActivity context, View anchor, ArrayList<ReaderAction> actions, final OnActionHandler onActionHandler, final OnOverflowHandler onOverflowHandler, int maxLines, int popupLocation) { 548 final ScrollView scroll = new ScrollView(context); 549 final CRToolBar tb = new CRToolBar(context, actions, true); 550 tb.setMaxLines(maxLines); 551 tb.setOnActionHandler(onActionHandler); 552 tb.setVertical(false); 553 tb.measure(MeasureSpec.makeMeasureSpec(anchor.getWidth(), MeasureSpec.EXACTLY), ViewGroup.LayoutParams.WRAP_CONTENT); 554 int w = tb.getMeasuredWidth(); 555 int h = tb.getMeasuredHeight(); 556 scroll.addView(tb); 557 scroll.setLayoutParams(new LayoutParams(w, h/2)); 558 scroll.setVerticalFadingEdgeEnabled(true); 559 scroll.setFadingEdgeLength(h / 10); 560 final PopupWindow popup = new PopupWindow(context); 561 tb.setPopup(popup, popupLocation); 562 ReaderAction longMenuAction = null; 563 for (ReaderAction action : actions) { 564 if (action.activateWithLongMenuKey()) 565 longMenuAction = action; 566 } 567 final ReaderAction foundLongMenuAction = longMenuAction; 568 569 popup.setTouchInterceptor((v, event) -> { 570 if ( event.getAction()==MotionEvent.ACTION_OUTSIDE ) { 571 popup.dismiss(); 572 return true; 573 } 574 return false; 575 }); 576 tb.setOnActionHandler(item -> { 577 popup.dismiss(); 578 return onActionHandler.onActionSelected(item); 579 }); 580 if (onOverflowHandler != null) 581 tb.setOnOverflowHandler(actions1 -> { 582 popup.dismiss(); 583 return onOverflowHandler.onOverflowActions(actions1); 584 }); 585 // close on menu or back keys 586 tb.setFocusable(true); 587 tb.setFocusableInTouchMode(true); 588 tb.setOnKeyListener((view, keyCode, event) -> { 589 if (event.getAction() == KeyEvent.ACTION_DOWN) { 590 if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) { 591 //popup.dismiss(); 592 return true; 593 } 594 } else if (event.getAction() == KeyEvent.ACTION_UP) { 595 if (keyCode == KeyEvent.KEYCODE_MENU && foundLongMenuAction != null && event.getDownTime() >= 500) { 596 popup.dismiss(); 597 return onActionHandler.onActionSelected(foundLongMenuAction); 598 } 599 if (keyCode == KeyEvent.KEYCODE_MENU || keyCode == KeyEvent.KEYCODE_BACK) { 600 popup.dismiss(); 601 return true; 602 } 603 } 604 return false; 605 }); 606 //popup.setBackgroundDrawable(new BitmapDrawable()); 607 popup.setWidth(WindowManager.LayoutParams.FILL_PARENT); 608 int hh = h; 609 int maxh = anchor.getHeight(); 610 if (hh > maxh - context.getPreferredItemHeight()) 611 hh = maxh - context.getPreferredItemHeight() * 3 / 2; 612 popup.setHeight(hh); 613 popup.setFocusable(true); 614 popup.setFocusable(true); 615 popup.setTouchable(true); 616 popup.setOutsideTouchable(true); 617 popup.setContentView(scroll); 618 InterfaceTheme theme = context.getCurrentTheme(); 619 Drawable bg; 620 if (theme.getPopupToolbarBackground() != 0) 621 bg = context.getResources().getDrawable(theme.getPopupToolbarBackground()); 622 else 623 bg = Utils.solidColorDrawable(theme.getPopupToolbarBackgroundColor()); 624 popup.setBackgroundDrawable(bg); 625 int [] location = new int[2]; 626 anchor.getLocationOnScreen(location); 627 int popupY = location[1]; 628 if (popupLocation == Settings.VIEWER_TOOLBAR_BOTTOM) 629 popup.showAtLocation(anchor, Gravity.BOTTOM | Gravity.FILL_HORIZONTAL, 0, 0); //location[0], popupY - anchor.getHeight()); 630 else 631 popup.showAtLocation(anchor, Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0); //, location[0], popupY); 632 return popup; 633 } 634 635 private boolean nightMode; updateNightMode(boolean nightMode)636 public void updateNightMode(boolean nightMode) { 637 if (this.nightMode != nightMode) { 638 this.nightMode = nightMode; 639 if (isShown()) { 640 requestLayout(); 641 invalidate(); 642 } 643 } 644 } 645 onThemeChanged(InterfaceTheme theme)646 public void onThemeChanged(InterfaceTheme theme) { 647 //buttonAlpha = theme.getToolbarButtonAlpha(); 648 //textColor = theme.getStatusTextColor(); 649 if (isShown()) { 650 requestLayout(); 651 invalidate(); 652 } 653 } 654 } 655