/* textview.h
 * This file belongs to Worker, a file manager for UN*X/X11.
 * Copyright (C) 2005-2025 Ralf Hoffmann.
 * You can contact me at: ralf@boomerangsworld.de
 *   or http://www.boomerangsworld.de/worker
 *
 * 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 2 of the License, or
 * (at your option) any later version.
 *
 * 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.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef TEXTVIEW_H
#define TEXTVIEW_H

#include "awindow.h"
#include "guielement.h"
#include "callback.h"
#include "slider.h"
#include "textstorage.h"
#include "pan_scrolling.hh"

class TVCallBack : public CallBack
{
public:
  TVCallBack( class TextView *_tv );
  ~TVCallBack();
  TVCallBack( const TVCallBack &other );
  TVCallBack &operator=( const TVCallBack &other );
  
  void run_int( Widget *, int value ) override;
private:
  class TextView *tv;
};

class TextView : public AWindow {
public:
  TextView( AGUIX *parent,
            int x,
            int y,
            int width,
            int height,
            std::string title,
            std::shared_ptr< TextStorage > ts );
  ~TextView();
  TextView( const TextView &other );
  TextView &operator=( const TextView &other );
  bool handleMessage(XEvent *,Message *msg);
    bool handleKeyMessage( KeySym key,
                           unsigned int keystate );
  void gui_callback( Widget *, int value );
  void redraw();
  int setFont( const char *fontname );
  void setLineWrap( bool nv );
  bool getLineWrap() const;
  void setDisplayFocus( bool nv );
  bool getDisplayFocus() const;
  void maximizeX( int max_width = 0 );
  void maximizeYLines( int max_lines, int width = 0 );

  void setShowLineNumbers( bool nv );
  bool getShowLineNumbers() const;

  bool jumpToLine( int line_nr, bool highlight_line = false );

  class ColorDef
  {
  public:
    ColorDef();
    ~ColorDef();

    void setBackground( int col );
    int getBackground() const;

    void setTextColor( int col );
    int getTextColor() const;

    void setHighlightedFG( int col );
    int getHighlightedFG() const;

    void setHighlightedBG( int col );
    int getHighlightedBG() const;

    void setSelectionFG( int col );
    int getSelectionFG() const;

    void setSelectionBG( int col );
    int getSelectionBG() const;
  private:
    int _background, _textcolor;
    int _highlighted_fg, _highlighted_bg;
    int _selection_fg, _selection_bg;
  };

  void setColors( const ColorDef &col );
  ColorDef getColors() const;

  void textStorageChanged();
  void replaceTextStorage( std::shared_ptr< TextStorage > ts );

  void setSelectionStart( int unwrapped_line_nr, int offset );
  void getSelectionStart( int &unwrapped_line_nr, int &offset ) const;
  void setSelectionEnd( int unwrapped_line_nr, int offset );
  void getSelectionEnd( int &unwrapped_line_nr, int &offset ) const;
  void clearSelection();
    void selectAll();

  void sizeChanged( int width, int height, bool explicit_resize );

  void makeSelectionVisible();

  int getYOffset();

    void showFrame( bool nv );

    void forceRedraw();

    bool isAtEnd() const;
    void scrollToEnd();

    void unsetHighlightLine();
protected:
  class AContainer *cont;
  Slider *hbar, *vbar;
  std::shared_ptr< TextStorage > m_ts;
  class AGUIXFont *font;
  TVCallBack tvcb;
  bool _show_line_numbers;

  int last_w, last_h, last_cont_width;
  bool line_wrap;
  bool _display_focus;
  struct timeval _lastwheel;
  
  struct {
      int real_line_number;
      int y_offset;
  } _highlight_line;

  ColorDef _colors;

  struct {
      int start_uline;
      int start_offset;
      int end_uline;
      int end_offset;
  } m_selection;

  Pixmap m_buffer;

    bool m_show_frame;

    bool m_selection_scroll_active = false;
  
    pan_info m_pan_info;

    static unsigned int s_scroll_button, s_scroll_buttonmask, s_scroll_mod;

    AGUIX::mouse_click_mode m_click_mode = AGUIX::NO_CLICK;
    Time m_last_click_time = {0};
    struct {
        int x;
        int y;
    } m_first_click_pos = { 0, 0 };
    std::pair< int, int > m_first_click_text_pos = { 0, 0 };

  void boxRedraw();
  void createContainer();
  void updateBars();
  void getLinesWidth( int &lines, int &width ) const;
  void doCreateStuff();
  void doDestroyStuff();

  void prepareBG( bool force = false );
  int getHScrollStep() const;

  int getTextStartOffset() const;

  void initColors();

  void updateHBarForVisibleLines();

  void drawLineNumbers( int start_x, int end_x, int start_y, int lines );
  void drawLines( int start_x, int start_y, int width, int lines );

  void drawBuffer();
  void drawBuffer( int dx, int dy, int dw, int dh );
  void updateBuffer();

  void checkBuffer();

    void setVBarOffset( int offset );
    void checkForEndReached();

    std::pair< int, int >  getTextPosForMousePos( int x, int y );

    void copySelectionToClipboard();

    int scrollView( int xdelta, int ydelta );
    void updateSelection( int mx, int my, bool initial );
    void getTextArea( int &x, int &y,
                      int &w, int &h );
    void handleThird( Message *msg );

    std::pair< std::pair< int, int >,
               std::pair< int, int > > getSelectionElement( const std::pair< int, int > &pos );

    bool isNearFirstClick( int mx, int my ) const;
};

#endif

/* Local Variables: */
/* mode:c++ */
/* End: */
