diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index 5dd3d37..ba21a89 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -450,7 +450,6 @@ void onKeypress(u8 note) void onKeyrelease(void) { - // stop cursor } void handleNoteStroke(u8 note) @@ -645,7 +644,7 @@ void handleSampleChange(const u16 newsample) return; } - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, newsample, lbinstruments->getidx()); sampledisplay->hideLoopPoints(); nssamplevolume->setValue( (smp->getVolume()+1)/4 ); nspanning->setValue(smp->getPanning()/2); @@ -657,7 +656,8 @@ void handleSampleChange(const u16 newsample) else rbg_sampleloop->setActive(0); - updateKeyLabels(); + if (fxkb->is_visible()) updateKeyLabels(); + if (!had_changes) setHasUnsavedChanges(false); /* printf("Selected:"); @@ -674,7 +674,6 @@ void handleSampleChange(const u16 newsample) */ } - void volEnvSetInst(Instrument *inst) { bool had_unsaved = state->unsaved_changes; @@ -748,6 +747,21 @@ void updateTempoAndBpm(void) nbtempo->setValue(song->getTempo()); } +void cursorTimerHandler(void) +{ + sampledisplay->calcCursor(); +} + +void startCursorTimer(void) +{ + TIMER1_DATA = TIMER_FREQ_64(60); // Call handler every frame + TIMER1_CR = TIMER_ENABLE | TIMER_IRQ_REQ | TIMER_DIV_64; + irqSet(IRQ_TIMER1, cursorTimerHandler); + irqEnable(IRQ_TIMER1); +} + + + void setSong(Song *newsong) { song = newsong; @@ -816,7 +830,7 @@ void setSong(Song *newsong) inst = song->getInstrument(state->instrument); if(inst != NULL) { - sampledisplay->setSample(inst->getSample(state->sample)); + sampledisplay->setSample(inst->getSample(state->sample), state->sample, state->instrument); } strncpy(str, song->getName(), sizeof(str)-1); @@ -2163,6 +2177,7 @@ void destroyThemeDialog(void) redrawSubScreen(); } + void reloadSkin(void) { gui->setTheme(settings->getTheme(), settings->getTheme()->col_bg); @@ -2174,6 +2189,7 @@ void reloadSkin(void) u32 colcol = col | col << 16; dmaFillWords(colcol, sub_vram + (256 * y) + 224, (256 - 224) * 2); } + gui->draw(); redrawSubScreen(); setRecordMode(state->recording); @@ -2963,7 +2979,7 @@ void sample_del_selection(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -2985,7 +3001,7 @@ void sample_fade_in(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -3007,7 +3023,7 @@ void sample_fade_out(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -3032,7 +3048,7 @@ void sample_reverse(void) DC_FlushAll(); - sampledisplay->setSample(smp); + sampledisplay->setSample(smp, state->sample, state->instrument); setHasUnsavedChanges(true); } @@ -3367,6 +3383,15 @@ void sampleDrawToggle(bool on) sampledisplay->setDrawMode(on); } +void handleOverlayWidgetChange(u8 screen, bool visible) +{ + if (screen == SUB_SCREEN) + { + if (visible) oamDisable(&oamSub); + else oamEnable(&oamSub); + } +} + #define RIGHT_SIDE_BUTTON_WIDTH 30 #define RIGHT_SIDE_BUTTON_X 225 @@ -3374,7 +3399,7 @@ void setupGUI(bool dldi_enabled) { gui = new GUI(); gui->setTheme(settings->getTheme(), settings->getTheme()->col_bg); - + gui->setOnOverlayChanged(handleOverlayWidgetChange); kb = new Piano(0, 152, 224, 40, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram); kb->set_overdraw(false); kb->registerNoteCallback(handleNoteStroke); @@ -3382,7 +3407,7 @@ void setupGUI(bool dldi_enabled) fxkb = new FXKeyboard(0, 152, (uint16*)CHAR_BASE_BLOCK_SUB(0), (uint16*)SCREEN_BASE_BLOCK_SUB(1/*8*/), &sub_vram, onFxKeyPressed, false); fxkb->set_overdraw(false); - + pixmaplogo = new GradientIcon(98, 1, 80, 17, (const u32*) nitrotracker_logo_raw, &sub_vram); @@ -4275,6 +4300,9 @@ void VblankHandler(void) fastscroll = false; } + oamUpdate(&oamSub); + + // Easy Piano pak handling logic if (pianoIsInserted()) { @@ -4428,10 +4456,11 @@ int main(int argc, char **argv) { videoSetMode(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG2_ACTIVE); // Sub screen: Keyboard tiles, Typewriter tiles and ERB - videoSetModeSub(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE); + videoSetModeSub(MODE_5_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE | DISPLAY_BG2_ACTIVE | DISPLAY_SPR_ACTIVE | DISPLAY_SPR_1D); vramSetPrimaryBanks(VRAM_A_MAIN_BG_0x06000000, VRAM_B_MAIN_BG_0x06020000, - VRAM_C_SUB_BG_0x06200000 , VRAM_D_LCD); + VRAM_C_SUB_BG_0x06200000 , VRAM_D_SUB_SPRITE); + // SUB_BG0 for Piano Tiles videoBgEnableSub(0); @@ -4460,6 +4489,20 @@ int main(int argc, char **argv) { int sub_bg = bgInitSub(2, BgType_Bmp16, BgSize_B16_256x256, 2, 0); bgSetPriority(sub_bg, 0); + // Sample display cursors and loop handles + oamInit(&oamSub, SpriteMapping_1D_32, false); + + windowEnableSub(WINDOW_0); + + bgWindowEnable(sub_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); + bgWindowEnable(piano_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); + bgWindowEnable(typewriter_bg, (WINDOW)(WINDOW_0|WINDOW_OUT)); + + windowSetBoundsSub(WINDOW_0, 5, 24, 5+129, 23+61); // sampledisplay x1,y1,x2,y2 + oamWindowEnable(&oamSub, WINDOW_0); + + + // Special effects #ifdef DEBUG REG_BLDCNT = BLEND_ALPHA | BLEND_SRC_BG0 | BLEND_DST_BG2; @@ -4530,9 +4573,18 @@ int main(int argc, char **argv) { CommandSetSong(song); setupGUI(fat_success); + + startCursorTimer(); + SampleCursor *scursors = (SampleCursor*)ntxm_ccalloc(MAX_CHANNELS, sizeof(SampleCursor)); + CommandSetCursorPosPtr(scursors); + sampledisplay->setCursorPosPtr((SampleCursor*)memUncached(scursors)); + action_buffer->register_change_callback({&actionBufferChangeCallback}); applySettings(); + + + setSong(song); #ifndef DEBUG diff --git a/arm9/source/tobkit/sampledisplay.cpp b/arm9/source/tobkit/sampledisplay.cpp index 579a368..e766249 100644 --- a/arm9/source/tobkit/sampledisplay.cpp +++ b/arm9/source/tobkit/sampledisplay.cpp @@ -45,12 +45,74 @@ SampleDisplay::SampleDisplay(u8 _x, u8 _y, u8 _width, u8 _height, u16 **_vram, S scrollthingypos(0), scrollthingywidth(width-2*SCROLLBUTTON_HEIGHT+2), pen_x_on_scrollthingy(0), zoom_level(0), scrollpos(0), snap_to_zero_crossings(true), draw_mode(false) { + gfxSampleCursor = oamAllocateGfx(&oamSub, SpriteSize_16x32, SpriteColorFormat_16Color); + gfxLoopHandles = oamAllocateGfx(&oamSub, SpriteSize_8x8, SpriteColorFormat_16Color); + + *(gfxSampleCursor+64)=1; + + oamSub.oamRotationMemory[0].vdy = 0; // max y scale + + for (int c=0;c<16;++c) + { + oamSet(&oamSub, c, 256, 23, 0, 0, + SpriteSize_16x32, + SpriteColorFormat_16Color, + gfxSampleCursor, + 0, true, false, false, false, false); + } + + const unsigned int loophandleTiles[8] __attribute__((aligned(4)))= + { + 0x22000000, + 0x33200000, + 0x33320000, + 0x33332000, + 0x33333200, + 0x33333320, + 0x33333332, + 0x33333332 + }; + + memcpy(gfxLoopHandles, loophandleTiles, 32); + + // handles + for (int i=SPR_LOOPHANDLE_1_L;i<=SPR_LOOPHANDLE_2_R;++i) + { + oamSet(&oamSub, i, + 199, 25, + 0, + 1, + SpriteSize_8x8, SpriteColorFormat_16Color, + gfxLoopHandles, + -1, + false, + false, + i % 2 == 1, i > 17, // h-flip every other handle, v-flip the last two handles + false); + } + + // reuse cursors as part of the loop handles + for (int i=SPR_LOOPLINE_1;i<=SPR_LOOPLINE_2;++i) + { + oamSet(&oamSub, i, + 199, 0, + 0, + 1, + SpriteSize_16x32, SpriteColorFormat_16Color, + gfxSampleCursor, + 0, + true, + false, + false, false, + false); + } } SampleDisplay::~SampleDisplay(void) { - + oamFreeGfx(&oamSub, gfxSampleCursor); + oamFreeGfx(&oamSub, gfxLoopHandles); } void SampleDisplay::penDown(u8 px, u8 py) @@ -66,6 +128,8 @@ void SampleDisplay::penDown(u8 px, u8 py) u32 loop_start_pos = sampleToPixel(smp->getLoopStart());//smp->getLoopStart() * (width-2) / smp->getNSamples(); u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength());//(smp->getLoopStart() + smp->getLoopLength()) * (width-2) / smp->getNSamples(); + + if(isInRect(px-x, py-y, std::max((s32)0, (s32)loop_start_pos - (s32)LOOP_TRIANGLE_SIZE), DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE, loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT+2)) { @@ -178,6 +242,7 @@ void SampleDisplay::penMove(u8 px, u8 py) } smp->setLoopStartAndLength(newstart, newlength); } + else if(pen_on_scrollthingy) { scrollthingypos = ntxm_clamp(px - x - pen_x_on_scrollthingy - SCROLLBUTTON_HEIGHT, 0, width - 2*SCROLLBUTTON_HEIGHT+2 - scrollthingywidth); @@ -226,15 +291,109 @@ void SampleDisplay::penMove(u8 px, u8 py) draw(); } -void SampleDisplay::setSample(Sample *_smp) +void SampleDisplay::setCursorPosPtr(SampleCursor *cursorpos_) { - smp = _smp; + cursorpos = cursorpos_; +} + +void SampleDisplay::calcCursor() +{ + if (smp == 0) return; + for (int chn = 0; chn < 16; ++chn) + { + bool drawCursor = false; + + if (cursorpos[chn].instidx == 255 || !(cursorpos[chn].active)) + { + oamSub.oamMemory[chn].x = 256; + continue; + } + + SampleCursor *playingNote = &cursorpos[chn]; + + const u8 looptype = smp->getLoop(); + + const u64 loopstart = (u64)(smp->getLoopStart()) << 32; + const u64 looplen = (u64)(smp->getLoopLength()) << 32; + const u64 nsamps = (u64)(smp->getNSamples()) << 32; + const u64 loopend = loopstart + looplen; + + u8& looprev = playingNote->looprev; + u64& playpos = playingNote->playbackpos; + + const u64 step = (((u64)(playingNote->playbackfreq) /* * (u64)n_ticks */) << 32) / 60; // timer + + // are we going backwards? + if (looprev) { + // calculate position if we are "bouncing" from the start + if (step > playpos) { + playpos = loopstart + step - playpos; + looprev = false; + } + else + playpos -= step; + } + else + playpos += step; + + // if between frames the cursor jumped past the end of the sample put it in the correct position after the start + if (looptype == FORWARD_LOOP && playpos >= loopend) + playpos = loopstart + playpos - loopend; + + else if (looptype == PING_PONG_LOOP) { + // If we're going backwards but we jumped beyond the first loop handle, + // calculate where we should be. (loopstart + (loopstart - playpos)), where (loopstart - playpos) is the error + if (looprev && playpos <= loopstart) { + playpos = 2 * loopstart - playpos; + looprev = false; + } + else if (!looprev && playpos >= loopend) { + playpos = 2 * loopend - playpos; + looprev = true; + } + } + u16 draw_cursor_at=0; + if (looptype == NO_LOOP && playpos >= nsamps) { + cursorpos[chn].active=false; + playpos = 0; + drawCursor = false; + } + + if (looptype != NO_LOOP && looplen <= step && playpos > loopstart) + if (looptype == PING_PONG_LOOP && looprev) + playpos = loopend - (step % looplen); + else + playpos = loopstart + (step % looplen); + + draw_cursor_at = sampleToPixel(playpos >> 32); + + if (draw_cursor_at != 0 && cursorpos[chn].instidx == instidx && cursorpos[chn].smpidx == smpidx) + drawCursor = true; + + + oamSub.oamMemory[chn].x = !drawCursor ? 199 : draw_cursor_at-3; + } + +} + + +void SampleDisplay::setSample(Sample *_smp, u8 _smpidx, u8 _instidx) +{ + bool changed = false; selection_exists = false; selstart = selend = 0; if(_smp == 0) { loop_points_visible = false; } - draw(); + + if (smp != _smp || _smpidx != smpidx || instidx != _instidx) + changed = true; + + smpidx = _smpidx; + instidx = _instidx; + smp = _smp; + + if (changed) draw(); } void SampleDisplay::select_all(void) @@ -288,6 +447,18 @@ void SampleDisplay::setInactive(void) draw(); } +void SampleDisplay::setTheme(Theme *theme_, u16 bgcolor_) +{ + *(SPRITE_PALETTE_SUB+1) = theme_->col_sample_cursor; + + // palette index 1 + *(SPRITE_PALETTE_SUB+2+16) = theme_->col_outline; + *(SPRITE_PALETTE_SUB+3+16) = theme_->col_loop; + *(SPRITE_PALETTE_SUB+1+16) = theme_->col_loop; + + Widget::setTheme(theme_, bgcolor_); +} + void SampleDisplay::setDrawMode(bool _on) { draw_mode = _on; @@ -316,6 +487,20 @@ void SampleDisplay::setSnapToZeroCrossing(bool snap) snap_to_zero_crossings = snap; } + +void SampleDisplay::reveal(void) +{ + oamEnable(&oamSub); + Widget::reveal(); +} + +void SampleDisplay::occlude(void) +{ + oamDisable(&oamSub); + + Widget::occlude(); +} + /* ===================== PRIVATE ===================== */ long SampleDisplay::find_zero_crossing_near(long pos) @@ -501,7 +686,7 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); + bool draw_selection_here = (draw_selection && i >= selleft && i <= selright); u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; data = &(base[f32toint(pos)]); @@ -547,7 +732,7 @@ void SampleDisplay::draw(void) for(s32 i=1; i= selleft && i < selright); + bool draw_selection_here = (draw_selection && i >= selleft && i <= selright); u16 colortable_current = draw_selection_here ? theme->col_smp_waveform_sel : theme->col_smp_waveform; u16 bg_current = draw_selection_here ? theme->col_smp_bg_sel : theme->col_smp_bg; data = &(base[f32toint(pos)]); @@ -591,94 +776,39 @@ void SampleDisplay::draw(void) // // Loop Points // - if( (loop_points_visible) && (smp->getLoop() != NO_LOOP) && !draw_mode ) - { - s32 loop_start_pos = sampleToPixel(smp->getLoopStart()); - s32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); - - // Loop Start - - if( (loop_start_pos >= 0) && (loop_start_pos <= width-2) ) { - // Line - for(u8 i=1; icol_loop; - - /* unused - u8 cutoff = 0; - if(loop_start_pos < 1+LOOP_TRIANGLE_SIZE) - cutoff = 1+LOOP_TRIANGLE_SIZE - loop_start_pos; - */ - - // Left Triangle - if(loop_start_pos > 1 + LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_start_pos-2, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - for(u8 i=0; icol_loop); - drawPixel(loop_start_pos-i-3, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); - } + u32 loop_start_pos = sampleToPixel(smp->getLoopStart()); + u32 loop_end_pos = sampleToPixel(smp->getLoopStart() + smp->getLoopLength()); - drawHLine(loop_start_pos-LOOP_TRIANGLE_SIZE+1, DRAW_HEIGHT, LOOP_TRIANGLE_SIZE-1, - theme->col_loop); - drawPixel(loop_start_pos-LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); - } + bool draw_loop_end = ( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ); + bool draw_loop_start = (loop_start_pos >= 0) && (loop_start_pos <= width-2); - // Right Triangle - if(loop_start_pos < width - 2 - LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_start_pos+1, DRAW_HEIGHT+1-LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - for(u8 i=0; icol_loop); - drawPixel(loop_start_pos+3+i, DRAW_HEIGHT+2-LOOP_TRIANGLE_SIZE+i, theme->col_outline); - } - drawHLine(loop_start_pos+1, DRAW_HEIGHT-LOOP_TRIANGLE_SIZE+LOOP_TRIANGLE_SIZE, LOOP_TRIANGLE_SIZE-1, - theme->col_loop); - drawPixel(loop_start_pos+LOOP_TRIANGLE_SIZE, DRAW_HEIGHT, theme->col_outline); - } + if( (loop_points_visible) && (smp->getLoop() != NO_LOOP) && !draw_mode ) + { + if(draw_loop_start) + { + oamSetXY(&oamSub, SPR_LOOPHANDLE_1_L, loop_start_pos-2, DRAW_HEIGHT+18); + oamSetXY(&oamSub, SPR_LOOPHANDLE_1_R, loop_start_pos-2+8-1, DRAW_HEIGHT+18); + oamSetXY(&oamSub, SPR_LOOPLINE_1, loop_start_pos-2-1, y); } + else + oamSetXY(&oamSub, SPR_LOOPLINE_1, width+1, y); - // Loop End - - if( (loop_end_pos >= 0) && (loop_end_pos <= width-2) ) { - // Line - for(u8 i=1; icol_loop; - - // Left Triangle - if(loop_end_pos > 1 + LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_end_pos-LOOP_TRIANGLE_SIZE+1, 1, LOOP_TRIANGLE_SIZE-1, - theme->col_loop); - drawPixel(loop_end_pos-LOOP_TRIANGLE_SIZE, 1, theme->col_outline); - - for(u8 i=0; icol_loop); - drawPixel(loop_end_pos-1-LOOP_TRIANGLE_SIZE+i+1, 2+i, theme->col_outline); - } - - drawHLine(loop_end_pos-2, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - } - - // Right Triangle - if(loop_end_pos < width-1-LOOP_TRIANGLE_SIZE) - { - drawHLine(loop_end_pos+1, 1, LOOP_TRIANGLE_SIZE-1, theme->col_loop); - drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE, 1, theme->col_outline); - - for(u8 i=0; icol_loop); - drawPixel(loop_end_pos+LOOP_TRIANGLE_SIZE-i, 2+i, theme->col_outline); - } - - drawHLine(loop_end_pos+1, LOOP_TRIANGLE_SIZE, 2, theme->col_outline); - } + if(draw_loop_end) + { + oamSetXY(&oamSub, SPR_LOOPHANDLE_2_L, loop_end_pos-2, y); + oamSetXY(&oamSub, SPR_LOOPHANDLE_2_R, loop_end_pos-2+8-1, y); + oamSetXY(&oamSub, SPR_LOOPLINE_2, loop_end_pos-2-1, y); } + else + oamSetXY(&oamSub, SPR_LOOPLINE_2, width+1, y); } + oamSetHidden(&oamSub, SPR_LOOPHANDLE_1_L, !draw_loop_start); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_1_R, !draw_loop_start); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_2_L, !draw_loop_end); + oamSetHidden(&oamSub, SPR_LOOPHANDLE_2_R, !draw_loop_end); + // // Zoom buttons // diff --git a/arm9/source/tobkit/sampledisplay.h b/arm9/source/tobkit/sampledisplay.h index c201b5a..94ef5b7 100644 --- a/arm9/source/tobkit/sampledisplay.h +++ b/arm9/source/tobkit/sampledisplay.h @@ -33,14 +33,22 @@ namespace tobkit { #define LOOP_TRIANGLE_SIZE 8 #define SNAP_TO_ZERO_CROSSING_RADIUS 32 // Search 32 samples to the left and to the right to find a zero crossing -#define SCROLLBAR_WIDTH 9 -#define SCROLLBUTTON_HEIGHT 9 +#define SCROLLBAR_WIDTH 9 +#define SCROLLBUTTON_HEIGHT 9 #define SAMPLE_MAX_ZOOM 16 -#define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed -#define MIN_SCROLLTHINGY_WIDTH 15 -#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-2) // height of the visible window +#define SCROLLPIXELS 25 // Scroll that many pixels when a scroll button is pressed +#define MIN_SCROLLTHINGY_WIDTH 15 +#define DRAW_HEIGHT (height-SCROLLBUTTON_HEIGHT-3) // height of the visible window + +#define SPR_SCURSOR(n) (n) +#define SPR_LOOPHANDLE_1_L 16 +#define SPR_LOOPHANDLE_1_R 17 +#define SPR_LOOPHANDLE_2_L 18 +#define SPR_LOOPHANDLE_2_R 19 +#define SPR_LOOPLINE_1 20 +#define SPR_LOOPLINE_2 21 class SampleDisplay: public Widget { public: @@ -55,12 +63,15 @@ class SampleDisplay: public Widget { // Drawing request void pleaseDraw(void); - - void setSample(Sample *_smp); - + void reveal(void); + + void setSample(Sample *_smp, u8 smpidx=0, u8 instidx=255); void select_all(void); void clear_selection(void); + void calcCursor(); + void setCursorPosPtr(SampleCursor *cursorpos); + // Return start and end sample of selection bool getSelection(u32 *startsample, u32 *endsample); @@ -68,6 +79,8 @@ class SampleDisplay: public Widget { void setActive(void); void setInactive(void); + void setTheme(Theme *theme_, u16 bgcolor_); + void setDrawMode(bool _on); void showLoopPoints(void); @@ -75,6 +88,7 @@ class SampleDisplay: public Widget { void setSnapToZeroCrossing(bool snap); + void occlude(void); private: // Finds a zero corssing in the sample near pos, returns sample when successful, -1 else long find_zero_crossing_near(long pos); @@ -88,7 +102,7 @@ class SampleDisplay: public Widget { s32 sampleToPixel(u32 sample); Sample *smp; - + u8 smpidx, instidx; u32 selstart, selend; bool selection_exists; @@ -118,6 +132,9 @@ class SampleDisplay: public Widget { bool draw_mode; u8 draw_last_x, draw_last_y; + + SampleCursor *cursorpos; + u16 *gfxSampleCursor, *gfxLoopHandles; }; }; diff --git a/tobkit/include/tobkit/gui.h b/tobkit/include/tobkit/gui.h index 5c6ec9d..7ac6241 100644 --- a/tobkit/include/tobkit/gui.h +++ b/tobkit/include/tobkit/gui.h @@ -57,6 +57,9 @@ class GUI { // Remove the overlay widget void unregisterOverlayWidget(u8 screen = SUB_SCREEN); + // Event handler for when an overlay widget is about to draw. (so we can clean up widgets underneath) + void setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)); + // Event calls void penDown(u8 x, u8 y); void penUp(u8 x, u8 y); // Remove the coordinates here! @@ -90,6 +93,7 @@ class GUI { Widget *activeWidget; u8 activeScreen; Widget *overlayWidgetMain, *overlayWidgetSub; + void (*onOverlayChanged)(u8, bool); u16 overlayShortcuts; Theme *theme; u16 bgcolor; diff --git a/tobkit/include/tobkit/theme.h b/tobkit/include/tobkit/theme.h index b2920a3..b1946ef 100644 --- a/tobkit/include/tobkit/theme.h +++ b/tobkit/include/tobkit/theme.h @@ -22,7 +22,7 @@ limitations under the License. #include "../../arm9/source/tools.h" #include -#define NUM_COLORS 112 +#define NUM_COLORS 113 namespace tobkit { @@ -142,6 +142,7 @@ struct ColorScheme { u16 col_fxkeyboard_cmd_desc_disabled; u16 col_fxkeyboard_minilabel_x; u16 col_fxkeyboard_minilabel_y; + u16 col_sample_cursor; }; }; diff --git a/tobkit/source/gui.cpp b/tobkit/source/gui.cpp index d8f153e..f532a02 100644 --- a/tobkit/source/gui.cpp +++ b/tobkit/source/gui.cpp @@ -23,7 +23,7 @@ using namespace tobkit; /* ===================== PUBLIC ===================== */ GUI::GUI() - :activeWidget(0), activeScreen(SUB_SCREEN), overlayWidgetMain(0), + :activeWidget(0), activeScreen(SUB_SCREEN), onOverlayChanged(0), overlayWidgetMain(0), overlayWidgetSub(0), overlayShortcuts(0) { u8 i; @@ -103,8 +103,10 @@ void GUI::unregisterWidget(Widget *w) void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) { if(screen == SUB_SCREEN) { + onOverlayChanged(SUB_SCREEN, true); overlayWidgetSub = w; } else { + onOverlayChanged(MAIN_SCREEN, true); overlayWidgetMain = w; } overlayShortcuts = listeningButtons; @@ -116,11 +118,13 @@ void GUI::registerOverlayWidget(Widget *w, u16 listeningButtons, u8 screen) void GUI::unregisterOverlayWidget(u8 screen) { if(screen == SUB_SCREEN) { + onOverlayChanged(SUB_SCREEN, false); if(activeWidget==overlayWidgetSub) { activeWidget = 0; } overlayWidgetSub = 0; } else { + onOverlayChanged(MAIN_SCREEN, false); if(activeWidget==overlayWidgetMain) { activeWidget = 0; } @@ -129,6 +133,12 @@ void GUI::unregisterOverlayWidget(u8 screen) overlayShortcuts = 0; } + +void GUI::setOnOverlayChanged(void (*_onOverlayChanged)(u8, bool)) +{ + onOverlayChanged = _onOverlayChanged; +} + // Event calls void GUI::penDown(u8 x, u8 y) { diff --git a/tobkit/source/theme.cpp b/tobkit/source/theme.cpp index a323010..5830037 100644 --- a/tobkit/source/theme.cpp +++ b/tobkit/source/theme.cpp @@ -133,6 +133,7 @@ ColorScheme::ColorScheme() { col_fxkeyboard_cmd_desc_disabled = col_dark_ctrl_disabled; col_fxkeyboard_minilabel_x = col_pv_notes &~ BIT(15); col_fxkeyboard_minilabel_y = col_pv_effect &~ BIT(15); + col_sample_cursor = col_env_sustain; } Theme::Theme(char* themepath, bool use_fat) @@ -234,7 +235,7 @@ bool Theme::parseTheme(FILE* theme_, u16* theme_cols) { // check if specific colours were specified by the theme // if not replace them with their previous colour from the same theme - if (!theme_has_key[99]) theme_cols[99] = theme_cols[3]; // Sample editor zoom buttons + if (!theme_has_key[99]) theme_cols[99] = theme_cols[3]; // Sample editor zoom buttons if (!theme_has_key[100]) theme_cols[100] = theme_cols[13]; // Message box title gradient col1 if (!theme_has_key[101]) theme_cols[101] = theme_cols[14]; // Message box title gradient col2 if (!theme_has_key[102]) theme_cols[102] = theme_cols[27]; // Message box title text @@ -248,6 +249,8 @@ bool Theme::parseTheme(FILE* theme_, u16* theme_cols) { if (!theme_has_key[109]) theme_cols[109] = theme_cols[8]; // Fxkb disabled command desc label if (!theme_has_key[110]) theme_cols[110] = theme_cols[61]; // Fxkb button param label 'X' if (!theme_has_key[111]) theme_cols[111] = theme_cols[67]; // Fxkb button param label 'Y' + if (!theme_has_key[112]) theme_cols[112] = theme_cols[38]; // Sample cursor + return true; }